diff --git a/.gitignore b/.gitignore index 45a0e28a3ddfb1..b0b0f26c5d13af 100644 --- a/.gitignore +++ b/.gitignore @@ -53,3 +53,4 @@ TAGS tags .idea +*.bak diff --git a/arch/arm/include/aarch32/cortex_m/stack.h b/arch/arm/include/aarch32/cortex_m/stack.h index c6c6f57e5ef400..c1ff2269565791 100644 --- a/arch/arm/include/aarch32/cortex_m/stack.h +++ b/arch/arm/include/aarch32/cortex_m/stack.h @@ -26,7 +26,7 @@ extern "C" { #endif -extern K_KERNEL_STACK_ARRAY_DEFINE(z_interrupt_stacks, CONFIG_MP_NUM_CPUS, +K_KERNEL_STACK_ARRAY_EXTERN(z_interrupt_stacks, CONFIG_MP_NUM_CPUS, CONFIG_ISR_STACK_SIZE); /** diff --git a/boards/arm/npcm400f_evb/fun_def_list.h b/boards/arm/npcm400f_evb/fun_def_list.h index f3b2ca7dafdfd3..5b6c82ae254670 100644 --- a/boards/arm/npcm400f_evb/fun_def_list.h +++ b/boards/arm/npcm400f_evb/fun_def_list.h @@ -71,3 +71,11 @@ FUN_DEFINE(DT_NODELABEL(pinctrl_vin3_default), VIN3) FUN_DEFINE(DT_NODELABEL(pinctrl_spip_default), SPIP_CS, SPIP_SCLK, SPIP_DIO0, SPIP_DIO1) FUN_DEFINE(DT_NODELABEL(pinctrl_spip_quad), SPIP_DIO2, SPIP_DIO3) #endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(i3c0), okay) && CONFIG_I3C_NPCM4XX +FUN_DEFINE(DT_NODELABEL(pinctrl_i3c0_default), I3C1_SCL, I3C1_SDA) +#endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(i3c1), okay) && CONFIG_I3C_NPCM4XX +FUN_DEFINE(DT_NODELABEL(pinctrl_i3c1_default), I3C2_SCL, I3C2_SDA) +#endif diff --git a/boards/arm/npcm400f_evb/npcm400f_evb.dts b/boards/arm/npcm400f_evb/npcm400f_evb.dts index 494a65eb35c05e..7b7332229862cb 100644 --- a/boards/arm/npcm400f_evb/npcm400f_evb.dts +++ b/boards/arm/npcm400f_evb/npcm400f_evb.dts @@ -126,7 +126,7 @@ &i2c6a { clock-frequency = <200000>; - status = "okay"; + status = "disabled"; }; &i2c1b { @@ -164,3 +164,46 @@ &spip { status = "okay"; }; + +&i3c0 { + status = "okay"; + assigned-address = <0x20>; + i2c-scl-hz = <100000>; + i3c-scl-hz = <12500000>; + /* part-id = <0x1234>; */ + /* vendor-def-id = <0x567>; */ + bcr = <0x66>; + dcr = <0xCC>; + busno = <0x0>; + pinctrl-0 = <&pinctrl_i3c0_default>; +}; + +&i3c1 { + status = "okay"; + assigned-address = <0x21>; + i2c-scl-hz = <100000>; + i3c-scl-hz = <12500000>; + /* part-id = <0x1234>; */ + /* vendor-def-id = <0x5607>; */ + bcr = <0x66>; + dcr = <0xCC>; + slave; + secondary; + busno = <0x0>; + pinctrl-0 = <&pinctrl_i3c1_default>; + + /* #address-cells = <1>; */ + /* #size-cells = <0>; */ + + /* + * i3c1_smq:i3c-slave-mqueue@21 { + * compatible = "aspeed,i3c-slave-mqueue"; + * reg = <0x21>; + * msg-size = <256>; + * num-of-msgs = <4>; + * mandatory-data-byte = <0xbf>; + * label = "I3C_1_SMQ"; + * status = "okay"; + * }; + */ +}; diff --git a/boards/arm/npcm400f_evb/npcm400f_evb_defconfig b/boards/arm/npcm400f_evb/npcm400f_evb_defconfig index 52a3af6dc99c01..8c2eb36dc44f46 100644 --- a/boards/arm/npcm400f_evb/npcm400f_evb_defconfig +++ b/boards/arm/npcm400f_evb/npcm400f_evb_defconfig @@ -47,8 +47,8 @@ CONFIG_WDT_NPCM4XX=y CONFIG_NPCM4XX_MIWU=y # PECI driver -CONFIG_PECI=y -CONFIG_PECI_NPCM4XX=y +#CONFIG_PECI=y +#CONFIG_PECI_NPCM4XX=y #Counter Driver CONFIG_COUNTER=y @@ -77,4 +77,8 @@ CONFIG_ADC_NPCM4XX=y #SPIP Driver CONFIG_SPI=y -CONFIG_SPIP_NPCM4XX=y \ No newline at end of file +CONFIG_SPIP_NPCM4XX=y + +# I3C driver +CONFIG_I3C=y +CONFIG_I3C_NPCM4XX=y \ No newline at end of file diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index 4e60828a8077ee..ebda184a653edf 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -19,6 +19,7 @@ add_subdirectory_ifdef(CONFIG_GPIO gpio) add_subdirectory_ifdef(CONFIG_EC_HOST_CMD_PERIPH ec_host_cmd_periph) add_subdirectory_ifdef(CONFIG_I2C i2c) add_subdirectory_ifdef(CONFIG_I2S i2s) +add_subdirectory_ifdef(CONFIG_I3C i3c) add_subdirectory_ifdef(CONFIG_IEEE802154 ieee802154) add_subdirectory_ifdef(CONFIG_IPM ipm) add_subdirectory_ifdef(CONFIG_IPMI ipmi) diff --git a/drivers/Kconfig b/drivers/Kconfig index af301a00251fa8..10e898056dae03 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -41,6 +41,8 @@ source "drivers/i2c/Kconfig" source "drivers/i2s/Kconfig" +source "drivers/i3c/Kconfig" + source "drivers/pwm/Kconfig" source "drivers/pinmux/Kconfig" diff --git a/drivers/i3c/CMakeLists.txt b/drivers/i3c/CMakeLists.txt new file mode 100644 index 00000000000000..2bdcf3f985ddfc --- /dev/null +++ b/drivers/i3c/CMakeLists.txt @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources(i3c_common.c) + +zephyr_library_sources_ifdef(CONFIG_I3C_ASPEED i3c_global_aspeed.c) +#zephyr_library_sources_ifdef(CONFIG_I3C_ASPEED i3c_aspeed.c) + +add_subdirectory_ifdef(CONFIG_I3C_NPCM4XX NPCM4XX) +zephyr_library_sources_ifdef(CONFIG_I3C_NPCM4XX i3c_npcm4xx.c) +#zephyr_library_sources_ifdef(CONFIG_I3C_SHELL i3c_shell.c) +#add_subdirectory_ifdef(CONFIG_I3C_SLAVE slave) diff --git a/drivers/i3c/Kconfig b/drivers/i3c/Kconfig new file mode 100644 index 00000000000000..b3f67b77c51a58 --- /dev/null +++ b/drivers/i3c/Kconfig @@ -0,0 +1,27 @@ +# I3C options + +menuconfig I3C + bool "I3C Drivers" + help + Enable I3C Driver. + +if I3C + +config I3C_SHELL + bool "Enable I3C Shell" + default y + depends on SHELL + select SHELL_GETOPT + help + Enable I3C Shell. + +module = I3C +module-str = i3c +source "subsys/logging/Kconfig.template.log_config" + +#source "drivers/i3c/slave/Kconfig" + +# Include these first so that any properties (e.g. defaults) below can be +# overridden (by defining symbols in multiple locations) +source "drivers/i3c/Kconfig.npcm4xx" +endif # I3C diff --git a/drivers/i3c/Kconfig.npcm4xx b/drivers/i3c/Kconfig.npcm4xx new file mode 100644 index 00000000000000..6d27d6a86a2c60 --- /dev/null +++ b/drivers/i3c/Kconfig.npcm4xx @@ -0,0 +1,10 @@ +# NPCM4XX I3C driver configuration options + +# Copyright (c) 2023 Nuvoton Technology Corporation. +# SPDX-License-Identifier: Apache-2.0 + +config I3C_NPCM4XX + bool "NPCM4XX I3C driver" + depends on SOC_FAMILY_NPCM4XX + help + This option enables the I3C master driver for SOC_NPCM400F SoCs. diff --git a/drivers/i3c/NPCM4XX/CMakeLists.txt b/drivers/i3c/NPCM4XX/CMakeLists.txt new file mode 100644 index 00000000000000..a6d8e31ff37ea9 --- /dev/null +++ b/drivers/i3c/NPCM4XX/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright (c) 2023 Nuvoton Technology Corporation. +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources_ifdef(CONFIG_I3C_NPCM4XX i3c_core.c) +zephyr_sources_ifdef(CONFIG_I3C_NPCM4XX i3c_master.c) +zephyr_sources_ifdef(CONFIG_I3C_NPCM4XX i3c_slave.c) +zephyr_sources_ifdef(CONFIG_I3C_NPCM4XX api_i3c.c) \ No newline at end of file diff --git a/drivers/i3c/NPCM4XX/api_i3c.c b/drivers/i3c/NPCM4XX/api_i3c.c new file mode 100644 index 00000000000000..5906866caa250a --- /dev/null +++ b/drivers/i3c/NPCM4XX/api_i3c.c @@ -0,0 +1,477 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +extern I3C_BUS_INFO_t gBus[]; +extern I3C_DEVICE_INFO_t gI3c_dev_node_internal[]; +extern I3C_REG_ITEM_t *pSlaveReg[]; + +void api_I3C_Reset(__u8 busNo) +{ + if (busNo >= I3C_BUS_COUNT_MAX) { + return; + } + + I3C_Reset(busNo); +} + +I3C_ErrCode_Enum api_I3C_START(void) +{ + I3C_Setup_Internal_Device(); + I3C_Setup_External_Device(); + I3C_Setup_Bus(); + + return I3C_ERR_OK; +} + +__u8 I3C_Task_Engine(void) +{ + _Bool bTaskExist = FALSE; + + I3C_DEVICE_INFO_SHORT_t *pDev; + I3C_TRANSFER_TASK_t *pTask; + I3C_TASK_INFO_t *pTaskInfo; + I3C_PORT_Enum port; + I3C_DEVICE_INFO_t *pDevice; + I3C_BUS_INFO_t *pBus; + + for (port = I3C1_IF; port < I3C_PORT_MAX; port++) { + pDevice = &gI3c_dev_node_internal[port]; + if (pDevice->mode == I3C_DEVICE_MODE_DISABLE) { + continue; + } + + /* continue if internal devices connect to bus */ + if (pDevice->pOwner == NULL) { + continue; + } + + pBus = pDevice->pOwner; + + /* wait until bus is ready */ + if (pBus->busState == I3C_BUS_STATE_DEFAULT) { + if ((pDevice->mode == I3C_DEVICE_MODE_SLAVE_ONLY) || + (pDevice->mode == I3C_DEVICE_MODE_SECONDARY_MASTER)) { + /* dynamic address is assigned ? hot join ? */ + pDevice->dynamicAddr = hal_i3c_get_dynamic_address(port); + pDevice->bRunI3C = TRUE; + } + + continue; + } + + if (pBus->busState == I3C_BUS_STATE_WAIT_RESET_DONE) { + continue; + } + + if (pBus->busState == I3C_BUS_STATE_WAIT_CLEAR_DONE) { + continue; + } + + /* bus is busy, keep running current task until task done or timeout */ + if (pBus->pCurrentTask != NULL) { + continue; + } + + /* bus is free */ + if (pBus->busState == I3C_BUS_STATE_INIT) { + if (pBus->pCurrentMaster == pDevice) { + /* bus enumeration */ + if (IS_RSTDAA_DEVICE_PRESENT(pBus)) { + bTaskExist = TRUE; + I3C_CCCb_RSTDAA(pBus); + } else if (IS_SETHID_DEVICE_PRESENT(pBus)) { + bTaskExist = TRUE; + I3C_CCCb_SETHID(pBus); + } else if (IS_SETDASA_DEVICE_PRESENT(pBus)) { + bTaskExist = TRUE; + I3C_CCCw_SETDASA(pBus); + } else if (IS_SETAASA_DEVICE_PRESENT(pBus)) { + bTaskExist = TRUE; + I3C_CCCb_SETAASA(pBus); + } else { + bTaskExist = TRUE; + I3C_CCCb_ENTDAA(pBus); + } + } else { + if ((pDevice->mode == I3C_DEVICE_MODE_SLAVE_ONLY) || + (pDevice->mode == I3C_DEVICE_MODE_SECONDARY_MASTER)) { + /* dynamic address is assigned ? */ + pDevice->dynamicAddr = hal_i3c_get_dynamic_address(port); + pDevice->bRunI3C = TRUE; + + pDev = pDevice->pDevInfo; + if (pDev == NULL) { + continue; + } + + if (pDev->attr.b.reqHotJoin == 1) { + pDev->attr.b.reqHotJoin = 0; + } + } + } + } + + /* ============================================================== + * POST INIT TASK + * ============================================================== + */ + if (pDevice->mode == I3C_DEVICE_MODE_CURRENT_MASTER) { + if (pDevice->pTaskListHead == NULL) { + pDev = pBus->pDevList; + while (pDev != NULL) { + if ((pDev->attr.b.reqPostInit) && + (pDev->attr.b.donePostInit == 0)) { + /* run 1 post init task once in the task engine */ + /* if (IS_SPD5118_DEVICE(pDev->pDeviceInfo)) { + * bTaskExist = TRUE; + * SPD5118_Post_Init(pDev->staticAddr); + * break; + *} + */ + /* if (IS_LSM6DSO_DEVICE(pDev->pDeviceInfo)) { + * bTaskExist = TRUE; + * LSM6DSO_Post_Init(pDev); + * break; + *} + */ + } + + pDev = pDev->pNextDev; + } + } + } else if ((pDevice->mode == I3C_DEVICE_MODE_SLAVE_ONLY) || + (pDevice->mode == I3C_DEVICE_MODE_SECONDARY_MASTER)) { + /* hot-join */ + pDev = pDevice->pDevInfo; + if (pDev == NULL) { + continue; + } + + if ((pDev->attr.b.reqHotJoin == 1) && (pDev->attr.b.doneHotJoin == 0)) { + /* slave should try to do hot-join */ + } + } + + if (pDevice->pTaskListHead == NULL) { + continue; + } + + bTaskExist = TRUE; + pTask = pDevice->pTaskListHead; + pBus->pCurrentTask = pTask; + + pTaskInfo = pTask->pTaskInfo; + if (pTaskInfo->MasterRequest) { + I3C_Master_Start_Request((__u32)pTaskInfo); + } else { + I3C_Slave_Start_Request((__u32)pTaskInfo); + } + } + + return (bTaskExist == TRUE) ? 1 : 0; +} + +void api_I3C_Master_Start_Request(__u32 Parm) +{ + I3C_Master_Start_Request(Parm); +} + +void api_I3C_Slave_Start_Request(__u32 Parm) +{ + I3C_Slave_Start_Request(Parm); +} + +void api_I3C_Master_Stop(__u32 Parm) +{ + I3C_Master_Stop_Request(Parm); +} + +void api_I3C_Master_Run_Next_Frame(__u32 Parm) +{ + I3C_Master_Run_Next_Frame(Parm); +} + +void api_I3C_Master_New_Request(__u32 Parm) +{ + I3C_Master_New_Request(Parm); +} + +void api_I3C_Master_Insert_DISEC_After_IbiNack(__u32 Parm) +{ + I3C_Master_Insert_DISEC_After_IbiNack(Parm); +} + +void api_I3C_Master_IBIACK(__u32 Parm) +{ + I3C_Master_IBIACK(Parm); +} + +void api_I3C_Master_Insert_GETACCMST_After_IbiAckMR(__u32 Parm) +{ + I3C_Master_Insert_GETACCMST_After_IbiAckMR(Parm); +} + +void api_I3C_Master_Insert_ENTDAA_After_IbiAckHJ(__u32 Parm) +{ + I3C_Master_Insert_ENTDAA_After_IbiAckHJ(Parm); +} + +I3C_ErrCode_Enum api_I3C_Master_Callback(__u32 TaskInfo, I3C_ErrCode_Enum ErrDetail) +{ + I3C_Master_Callback(TaskInfo, ErrDetail); + return I3C_ERR_OK; +} + +I3C_ErrCode_Enum api_I3C_Slave_Callback(__u32 TaskInfo, I3C_ErrCode_Enum ErrDetail) +{ + I3C_Slave_Callback(TaskInfo, ErrDetail); + return I3C_ERR_OK; +} + +void api_I3C_Master_End_Request(__u32 Parm) +{ + I3C_Master_End_Request(Parm); +} + +void api_I3C_Slave_End_Request(__u32 Parm) +{ + I3C_Slave_End_Request(Parm); +} + +I3C_ErrCode_Enum api_I3C_connect_bus(I3C_PORT_Enum port, __u8 busNo) +{ + I3C_DEVICE_ATTRIB_t attr; + + if (port >= I3C_PORT_MAX) { + return I3C_ERR_PARAMETER_INVALID; + } + if (busNo >= I3C_BUS_COUNT_MAX) { + return I3C_ERR_PARAMETER_INVALID; + } + + I3C_DEVICE_INFO_t *pDevice; + I3C_BUS_INFO_t *pBus; + + pDevice = &gI3c_dev_node_internal[port]; + pBus = &gBus[busNo]; + + /* Build DevInfo for Bus */ + if (pDevice->mode != I3C_DEVICE_MODE_DISABLE) { + attr.U16 = 0; + attr.b.present = 1; + + if (pDevice->mode == I3C_DEVICE_MODE_CURRENT_MASTER) { + if (pBus->pCurrentMaster == NULL) { + pBus->pCurrentMaster = pDevice; + } + + attr.b.suppMST = 1; + attr.b.defaultMST = 1; + + pDevice->pDevInfo = NewDevInfo(pBus, pDevice, attr, pDevice->staticAddr, + pDevice->dynamicAddr, pDevice->pid, pDevice->bcr, pDevice->dcr); + } else { + attr.b.suppSLV = 1; + + attr.b.suppENTDAA = 1; + if (pDevice->staticAddr != I2C_STATIC_ADDR_DEFAULT_7BIT) { + attr.b.reqSETDASA = 1; + } + + pDevice->pDevInfo = NewDevInfo(pBus, pDevice, attr, pDevice->staticAddr, + I3C_DYNAMIC_ADDR_DEFAULT_7BIT, pDevice->pid, pDevice->bcr, + pDevice->dcr); + } + } + + pDevice->pOwner = pBus; + + return I3C_ERR_OK; +} + +I3C_ErrCode_Enum api_I3C_set_pReg(I3C_PORT_Enum port, I3C_REG_ITEM_t *pReg) +{ + I3C_DEVICE_INFO_t *pDevice; + + if (port >= I3C_PORT_MAX) { + return I3C_ERR_PARAMETER_INVALID; + } + + pDevice = &gI3c_dev_node_internal[port]; + pDevice->pReg = pReg; + return I3C_ERR_OK; +} + +/* + * I3C_ErrCode_Enum api_I3C_declare_lsm6dso(__u8 busNo, I3C_PORT_Enum port, + * __u8 address, __u16 InitMode) + * { + * return LSM6DSO_START(busNo, port, address, InitMode); + * } + * + * I3C_ErrCode_Enum api_I3C_declare_spd5118(__u8 busNo, I3C_PORT_Enum port, + * __u16 InitMode) + * { + * return SPD5118_START(busNo, port, InitMode); + * } + */ + +I3C_ErrCode_Enum api_I3C_bus_reset_done(__u8 busNo) +{ + return I3C_ERR_OK; +} + +extern __u8 bus_clear_counter; +I3C_ErrCode_Enum api_I3C_bus_clear_done(__u8 busNo) +{ + return I3C_ERR_OK; +} + +I3C_ErrCode_Enum api_I3C_Slave_Prepare_Response(I3C_DEVICE_INFO_t *pDevice, __u16 wrLen, + __u8 *pWrBuf) +{ + return I3C_Slave_Prepare_Response(pDevice, wrLen, pWrBuf); +} + +I3C_ErrCode_Enum api_I3C_Slave_Update_Pending(I3C_DEVICE_INFO_t *pDevice, __u8 mask) +{ + return I3C_Slave_Update_Pending(pDevice, mask); +} + +I3C_ErrCode_Enum api_I3C_Slave_Finish_Response(I3C_DEVICE_INFO_t *pDevice) +{ + return I3C_Slave_Finish_Response(pDevice); +} + +I3C_ErrCode_Enum api_I3C_Slave_Check_Response_Complete(I3C_DEVICE_INFO_t *pDevice) +{ + return I3C_Slave_Check_Response_Complete(pDevice); +} + +I3C_ErrCode_Enum api_I3C_Slave_Check_IBIDIS(I3C_DEVICE_INFO_t *pDevice, _Bool *bRet) +{ + return I3C_Slave_Check_IBIDIS(pDevice, bRet); +} + +I3C_DEVICE_INFO_t *api_I3C_Get_Current_Master_From_Port(I3C_PORT_Enum port) +{ + return Get_Current_Master_From_Port(port); +} + +I3C_BUS_INFO_t *api_I3C_Get_Bus_From_Port(I3C_PORT_Enum port) +{ + return Get_Bus_From_Port(port); +} + +I3C_ErrCode_Enum api_I3C_Setup_Master_Write_DMA(I3C_DEVICE_INFO_t *pDevice) +{ + return Setup_Master_Write_DMA(pDevice); +} + +I3C_ErrCode_Enum api_I3C_Setup_Master_Read_DMA(I3C_DEVICE_INFO_t *pDevice) +{ + return Setup_Master_Read_DMA(pDevice); +} + +I3C_ErrCode_Enum api_I3C_Setup_Slave_Write_DMA(I3C_DEVICE_INFO_t *pDevice) +{ + return Setup_Slave_Write_DMA(pDevice); +} + +I3C_ErrCode_Enum api_I3C_Setup_Slave_Read_DMA(I3C_DEVICE_INFO_t *pDevice) +{ + return Setup_Slave_Read_DMA(pDevice); +} + +I3C_ErrCode_Enum api_I3C_Setup_Slave_IBI_DMA(I3C_DEVICE_INFO_t *pDevice) +{ + return Setup_Slave_IBI_DMA(pDevice); +} + +I3C_DEVICE_INFO_SHORT_t *api_I3C_GetDevInfoByStaticAddr(I3C_BUS_INFO_t *pBus, __u8 slaveAddr) +{ + return GetDevInfoByStaticAddr(pBus, slaveAddr); +} + +I3C_DEVICE_INFO_SHORT_t *api_I3C_GetDevInfoByDynamicAddr(I3C_BUS_INFO_t *pBus, __u8 slaveAddr) +{ + return GetDevInfoByDynamicAddr(pBus, slaveAddr); +} + +I3C_DEVICE_INFO_t *api_I3C_Get_INODE(I3C_PORT_Enum port) +{ + if (port >= I3C_PORT_MAX) { + return NULL; + } + + return I3C_Get_INODE(port); +} + +I3C_PORT_Enum api_I3C_Get_IPORT(I3C_DEVICE_INFO_t *pDevice) +{ + return I3C_Get_IPORT(pDevice); +} + +I3C_TASK_INFO_t *api_I3C_Master_Create_Task(I3C_TRANSFER_PROTOCOL_Enum Protocol, __u8 Addr, + __u8 HSize, __u16 *pWrCnt, __u16 *pRdCnt, __u8 *WrBuf, __u8 *RdBuf, __u32 Baudrate, + __u32 Timeout, ptrI3C_RetFunc callback, __u8 PortId, I3C_TASK_POLICY_Enum Policy, + _Bool bHIF) +{ + return I3C_Master_Create_Task(Protocol, Addr, HSize, pWrCnt, pRdCnt, WrBuf, RdBuf, Baudrate, + Timeout, callback, PortId, Policy, bHIF); +} + +I3C_TASK_INFO_t *api_I3C_Slave_Create_Task(I3C_TRANSFER_PROTOCOL_Enum Protocol, __u8 Addr, + __u16 *pWrCnt, __u16 *pRdCnt, __u8 *WrBuf, __u8 *RdBuf, __u32 Timeout, + ptrI3C_RetFunc callback, __u8 PortId, _Bool bHIF) +{ + return I3C_Slave_Create_Task(Protocol, Addr, pWrCnt, pRdCnt, WrBuf, RdBuf, Timeout, + callback, PortId, bHIF); +} + +I3C_ErrCode_Enum api_I3C_Master_Insert_Task_ENTDAA(__u16 rxbuf_size, __u8 *rxbuf, __u32 Baudrate, + __u32 Timeout, ptrI3C_RetFunc callback, __u8 PortId, I3C_TASK_POLICY_Enum Policy, + _Bool bHIF) +{ + return I3C_Master_Insert_Task_ENTDAA(rxbuf_size, rxbuf, Baudrate, Timeout, callback, PortId, + Policy, bHIF); +} + +I3C_ErrCode_Enum api_I3C_Master_Insert_Task_CCCb(__u8 CCC, __u16 buf_size, __u8 *buf, + __u32 Baudrate, __u32 Timeout, ptrI3C_RetFunc callback, __u8 PortId, + I3C_TASK_POLICY_Enum Policy, _Bool bHIF) +{ + return I3C_Master_Insert_Task_CCCb(CCC, buf_size, buf, Baudrate, Timeout, callback, PortId, + Policy, bHIF); +} + +I3C_ErrCode_Enum api_I3C_Master_Insert_Task_CCCw(__u8 CCC, __u8 HSize, __u16 buf_size, __u8 *buf, + __u32 Baudrate, __u32 Timeout, ptrI3C_RetFunc callback, __u8 PortId, + I3C_TASK_POLICY_Enum Policy, _Bool bHIF) +{ + return I3C_Master_Insert_Task_CCCw(CCC, HSize, buf_size, buf, Baudrate, Timeout, callback, + PortId, Policy, bHIF); +} + +I3C_ErrCode_Enum api_I3C_Master_Insert_Task_CCCr(__u8 CCC, __u8 HSize, __u16 txbuf_size, + __u16 rxbuf_size, __u8 *txbuf, __u8 *rxbuf, __u32 Baudrate, __u32 Timeout, + ptrI3C_RetFunc callback, __u8 PortId, I3C_TASK_POLICY_Enum Policy, _Bool bHIF) +{ + return I3C_Master_Insert_Task_CCCr(CCC, HSize, txbuf_size, rxbuf_size, txbuf, rxbuf, + Baudrate, Timeout, callback, PortId, Policy, bHIF); +} + +I3C_ErrCode_Enum api_ValidateBuffer(I3C_TRANSFER_PROTOCOL_Enum Protocol, __u8 Address, __u8 HSize, + __u16 WrCnt, __u16 RdCnt, __u8 *WrBuf, __u8 *RdBuf, _Bool bHIF) +{ + return ValidateBuffer(Protocol, Address, HSize, WrCnt, RdCnt, WrBuf, RdBuf, bHIF); +} diff --git a/drivers/i3c/NPCM4XX/i3c_core.c b/drivers/i3c/NPCM4XX/i3c_core.c new file mode 100644 index 00000000000000..7daac08bdc0427 --- /dev/null +++ b/drivers/i3c/NPCM4XX/i3c_core.c @@ -0,0 +1,3446 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +I3C_BUS_INFO_t gBus[I3C_BUS_COUNT_MAX] = { + {.busno = 0, .DevCount = 0, .pDevList = NULL, .pCurrentMaster = NULL, + .busState = I3C_BUS_STATE_DEFAULT, .pCurrentTask = NULL}, + {.busno = 1, .DevCount = 0, .pDevList = NULL, .pCurrentMaster = NULL, + .busState = I3C_BUS_STATE_DEFAULT, .pCurrentTask = NULL}, +#if (I3C_BUS_COUNT_MAX > 2) + {.busno = 2, .DevCount = 0, .pDevList = NULL, .pCurrentMaster = NULL, + .busState = I3C_BUS_STATE_DEFAULT, .pCurrentTask = NULL}, + {.busno = 3, .DevCount = 0, .pDevList = NULL, .pCurrentMaster = NULL, + .busState = I3C_BUS_STATE_DEFAULT, .pCurrentTask = NULL}, + {.busno = 4, .DevCount = 0, .pDevList = NULL, .pCurrentMaster = NULL, + .busState = I3C_BUS_STATE_DEFAULT, .pCurrentTask = NULL}, + {.busno = 5, .DevCount = 0, .pDevList = NULL, .pCurrentMaster = NULL, + .busState = I3C_BUS_STATE_DEFAULT, .pCurrentTask = NULL}, +#endif +}; + +I3C_DEVICE_INFO_t gI3c_dev_node_internal[I3C_PORT_MAX] = { + {.port = I3C1_IF, .mode = I3C_DEVICE_MODE_DISABLE, .callback = NULL, + .pOwner = NULL, .pDevInfo = NULL, .task_count = 0, .pTaskListHead = NULL}, + {.port = I3C2_IF, .mode = I3C_DEVICE_MODE_DISABLE, .callback = NULL, + .pOwner = NULL, .pDevInfo = NULL, .task_count = 0, .pTaskListHead = NULL}, +#if (I3C_BUS_COUNT_MAX > 2) + {.port = I3C3_IF, .mode = I3C_DEVICE_MODE_DISABLE, .callback = NULL, + .pOwner = NULL, .pDevInfo = NULL, .task_count = 0, .pTaskListHead = NULL}, + {.port = I3C4_IF, .mode = I3C_DEVICE_MODE_DISABLE, .callback = NULL, + .pOwner = NULL, .pDevInfo = NULL, .task_count = 0, .pTaskListHead = NULL}, + {.port = I3C5_IF, .mode = I3C_DEVICE_MODE_DISABLE, .callback = NULL, + .pOwner = NULL, .pDevInfo = NULL, .task_count = 0, .pTaskListHead = NULL}, + {.port = I3C6_IF, .mode = I3C_DEVICE_MODE_DISABLE, .callback = NULL, + .pOwner = NULL, .pDevInfo = NULL, .task_count = 0, .pTaskListHead = NULL}, +#endif +}; + +uint8_t slvRxBuf[I3C_PORT_MAX][MAX_READ_LEN]; + +uint16_t slvRxLen[I3C_PORT_MAX] = { + MAX_READ_LEN, MAX_READ_LEN, +#if (I3C_BUS_COUNT_MAX > 2) + MAX_READ_LEN, MAX_READ_LEN, MAX_READ_LEN, MAX_READ_LEN +#endif +}; + +uint16_t slvRxOffset[I3C_PORT_MAX] = { + 0, 0, +#if (I3C_BUS_COUNT_MAX > 2) + 0, 0, 0, 0 +#endif +}; + + +/*-----------------------------------------------------------------------------------------*/ +/** + * @brief Used to customize Internal Devices for both I3C1 & I3C2 + * @return None + */ +/*------------------------------------------------------------------------------------------*/ +void I3C_Setup_Internal_Device(void) +{ + I3C_PORT_Enum port; + I3C_DEVICE_INFO_t *pDevice; + + for (port = I3C1_IF; port < I3C_PORT_MAX; port++) { + I3C_Port_Default_Setting(port); + + pDevice = &gI3c_dev_node_internal[port]; + hal_I3C_Config_Internal_Device(port, pDevice); + + /* validate mode setting */ + if ((pDevice->mode == I3C_DEVICE_MODE_CURRENT_MASTER) && + (pDevice->capability.MASTER == FALSE)) { + return; + } + + if ((pDevice->mode == I3C_DEVICE_MODE_SLAVE_ONLY) && + (pDevice->capability.SLAVE == FALSE)) { + return; + } + + if ((pDevice->mode == I3C_DEVICE_MODE_SECONDARY_MASTER) && + ((pDevice->capability.MASTER == FALSE) || + (pDevice->capability.SLAVE == FALSE))) { + return; + } + + /* validate for i3c/i2c device */ + if (pDevice->bRunI3C) { + if (!IsValidDynamicAddress(pDevice->dynamicAddr)) { + return; + } + } else { + if (!IsValidStaticAddress(pDevice->staticAddr)) { + return; + } + } + + if (pDevice->mode == I3C_DEVICE_MODE_DISABLE) { + pDevice->callback = NULL; + } else if (pDevice->mode == I3C_DEVICE_MODE_CURRENT_MASTER) { + pDevice->disableTimeout = TRUE; + pDevice->enableOpenDrainHigh = TRUE; + pDevice->enableOpenDrainStop = FALSE; + pDevice->callback = I3C_Master_Callback; + } else if (pDevice->mode == I3C_DEVICE_MODE_SLAVE_ONLY) { + pDevice->callback = I3C_Slave_Callback; + } else if (pDevice->mode == I3C_DEVICE_MODE_SECONDARY_MASTER) { + pDevice->callback = I3C_Slave_Callback; + } + + hal_I3C_Config_Device(pDevice); + } +} + +/*----------------------------------------------------------------------*/ +/** + * @brief User can define External Devices + * @return None + */ +/*----------------------------------------------------------------------*/ +void I3C_Setup_External_Device(void) +{ +} + +/*----------------------------------------------------------------------*/ +/** + * @brief Used to update bus state for bus enumeration or hot join + * @return None + */ +/*----------------------------------------------------------------------*/ +I3C_ErrCode_Enum I3C_Setup_Bus(void) +{ + I3C_PORT_Enum port; + I3C_DEVICE_INFO_t *pDevice; + I3C_BUS_INFO_t *pBus; + + for (port = I3C1_IF; port < I3C_PORT_MAX; port++) { + pDevice = &gI3c_dev_node_internal[port]; + pBus = pDevice->pOwner; + + if (pBus->busState == I3C_BUS_STATE_DEFAULT) { + if (pDevice->mode == I3C_DEVICE_MODE_DISABLE) { + continue; + } + + if (pDevice->mode == I3C_DEVICE_MODE_CURRENT_MASTER) { + /* bus master should perform bus enumeration later */ + if (pDevice == pBus->pCurrentMaster) { + pBus->busState = I3C_BUS_STATE_INIT; + } + } else { + /* slave might init by bus master or hot-join */ + } + } + } + + return I3C_ERR_OK; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief return internal device object by port no + * @return device object + */ +/*------------------------------------------------------------------------------*/ +I3C_DEVICE_INFO_t *I3C_Get_INODE(I3C_PORT_Enum port) +{ + return &gI3c_dev_node_internal[port]; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief return the bus master specified by the port + * @param [in] port port + * @return pointer to the device object which is current master of the bus + */ +/*------------------------------------------------------------------------------*/ +I3C_DEVICE_INFO_t *Get_Current_Master_From_Port(I3C_PORT_Enum port) +{ + I3C_BUS_INFO_t *pBus; + + if (port >= I3C_PORT_MAX) { + return NULL; + } + + pBus = Get_Bus_From_Port(port); + if (pBus == NULL) { + return NULL; + } + + return pBus->pCurrentMaster; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief return port no by its device object + * @return port no + */ +/*------------------------------------------------------------------------------*/ +I3C_PORT_Enum I3C_Get_IPORT(I3C_DEVICE_INFO_t *pDevice) +{ + I3C_PORT_Enum port; + + for (port = I3C1_IF; port < I3C_PORT_MAX; port++) { + if (pDevice == &gI3c_dev_node_internal[port]) { + return port; + } + } + + return I3C_PORT_MAX; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Validate dynamic address setting + * @return None + */ +/*------------------------------------------------------------------------------*/ +_Bool IsValidDynamicAddress(__u8 addr) +{ + if ((addr >= 0x08) && (addr <= 0x3D)) { + return TRUE; + } + + if ((addr >= 0x3F) && (addr <= 0x5D)) { + return TRUE; + } + + if ((addr >= 0x5F) && (addr <= 0x6D)) { + return TRUE; + } + + if ((addr >= 0x6F) && (addr <= 0x75)) { + return TRUE; + } + + if (addr == 0x77) { + return TRUE; + } + + return FALSE; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Validate static address setting + * @return None + */ +/*------------------------------------------------------------------------------*/ +_Bool IsValidStaticAddress(__u8 addr) +{ + if (addr == 0x7E) { + return FALSE; + } + + return TRUE; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Collect internal device's capability + * @param [in] port port + * @return Pass if return I3C_ERR_OK + */ +/*------------------------------------------------------------------------------*/ +I3C_ErrCode_Enum I3C_Port_Default_Setting(I3C_PORT_Enum port) +{ + I3C_DEVICE_INFO_t *pDevice; + + if (port >= I3C_PORT_MAX) { + return I3C_ERR_PARAMETER_INVALID; + } + + pDevice = &gI3c_dev_node_internal[port]; + pDevice->port = port; + + pDevice->capability.MASTER = hal_i3c_get_capability_support_master(port); + pDevice->capability.SLAVE = hal_i3c_get_capability_support_slave(port); + + pDevice->capability.FIFO_TX_LEN = hal_i3c_get_capability_Tx_Fifo_Len(port); + pDevice->capability.FIFO_RX_LEN = hal_i3c_get_capability_Rx_Fifo_Len(port); + + pDevice->capability.DMA = hal_i3c_get_capability_support_DMA(port); + pDevice->capability.INT = hal_i3c_get_capability_support_INT(port); + pDevice->capability.HDR_DDR = hal_i3c_get_capability_support_DDR(port); + pDevice->capability.ASYNC0 = hal_i3c_get_capability_support_ASYNC0(port); + pDevice->capability.IBI = hal_i3c_get_capability_support_IBI(port); + pDevice->capability.MASTER_REQUEST = hal_i3c_get_capability_support_Master_Request(port); + pDevice->capability.HOT_JOIN = hal_i3c_get_capability_support_Hot_Join(port); + + pDevice->capability.OFFLINE = hal_i3c_get_capability_support_Offline(port); + + pDevice->capability.I3C_VER_1p0 = hal_i3c_get_capability_support_V10(port); + pDevice->capability.I3C_VER_1p1 = hal_i3c_get_capability_support_V11(port); + + pDevice->mode = I3C_DEVICE_MODE_DISABLE; + pDevice->callback = NULL; + pDevice->bRunI3C = FALSE; + + pDevice->staticAddr = I2C_STATIC_ADDR_DEFAULT_7BIT; + pDevice->dynamicAddr = I3C_DYNAMIC_ADDR_DEFAULT_7BIT; + + memset(pDevice->pid, 0x00, sizeof(pDevice->pid)); + + pDevice->bcr = 0x00; + pDevice->dcr = 0x00; + pDevice->vendorID = 0; + pDevice->partNumber = 0; + + pDevice->pReg = NULL; + pDevice->cmdIndex = CMD_DEFAULT; + pDevice->stopSplitRead = FALSE; + + pDevice->enableOpenDrainHigh = FALSE; + pDevice->enableOpenDrainStop = FALSE; + pDevice->disableTimeout = TRUE; + pDevice->ackIBI = FALSE; + + /* pDevice->maxDataRate = 0; */ + + pDevice->pOwner = NULL; + pDevice->pDevInfo = NULL; + pDevice->task_count = 0; + pDevice->pTaskListHead = NULL; + + pDevice->pRxBuf = NULL; + pDevice->rxLen = 0; + pDevice->rxOffset = 0; + + pDevice->pTxBuf = NULL; + pDevice->txLen = 0; + pDevice->txOffset = 0; + + return I3C_ERR_OK; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief return bus object by bus no + * @param [in] busno bus no + * @return pointer to the bus object specified by the bus no + */ +/*------------------------------------------------------------------------------*/ +I3C_BUS_INFO_t *Get_Bus_From_BusNo(__u8 busno) +{ + if (busno >= I3C_BUS_COUNT_MAX) { + return NULL; + } + + return &gBus[busno]; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief return bus object by port + * @param [in] port I3C port + * @return pointer to the bus object specified by the port + */ +/*------------------------------------------------------------------------------*/ +I3C_BUS_INFO_t *Get_Bus_From_Port(I3C_PORT_Enum port) +{ + I3C_DEVICE_INFO_t *pDevice; + + if (port >= I3C_PORT_MAX) { + return NULL; + } + + pDevice = &gI3c_dev_node_internal[port]; + return pDevice->pOwner; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief validate bus state is idle or not ? + * @param [in] pBus bus object + * @return true, if the bus is idle or STOP + */ +/*------------------------------------------------------------------------------*/ +_Bool I3C_IS_BUS_KEEP_IDLE(I3C_BUS_INFO_t *pBus) +{ + I3C_PORT_Enum port; + I3C_DEVICE_INFO_t *pDevice; + + if (pBus == NULL) { + return FALSE; + } + + if (pBus->pCurrentMaster != NULL) { + pDevice = pBus->pCurrentMaster; + port = pDevice->port; + return hal_I3C_Is_Master_Idle(port); + } + + for (port = I3C1_IF; port < I3C_PORT_MAX; port++) { + if (Get_Bus_From_Port(port) == pBus) { + return hal_I3C_Is_Slave_Idle(port); + } + } + + return FALSE; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief validate bus state is DAA or not ? + * @param [in] pBus bus object + * @return true, if the bus is during DAA + */ +/*------------------------------------------------------------------------------*/ +_Bool I3C_IS_BUS_DURING_DAA(I3C_BUS_INFO_t *pBus) +{ + I3C_PORT_Enum port; + I3C_DEVICE_INFO_t *pDevice; + + if (pBus == NULL) { + return FALSE; + } + + if (pBus->pCurrentMaster != NULL) { + pDevice = pBus->pCurrentMaster; + port = pDevice->port; + return hal_I3C_Is_Master_DAA(port); + } + + for (port = I3C1_IF; port < I3C_PORT_MAX; port++) { + if (Get_Bus_From_Port(port) == pBus) { + return hal_I3C_Is_Slave_DAA(port); + } + } + + return FALSE; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief validate SLVSTART is detected or not ? + * @param [in] pBus bus object + * @return true, if the SLVSTART is detected + */ +/*------------------------------------------------------------------------------*/ +_Bool I3C_IS_BUS_DETECT_SLVSTART(I3C_BUS_INFO_t *pBus) +{ + I3C_PORT_Enum port; + I3C_DEVICE_INFO_t *pDevice; + + if (pBus == NULL) { + return FALSE; + } + + if (pBus->pCurrentMaster != NULL) { + pDevice = pBus->pCurrentMaster; + port = pDevice->port; + return hal_I3C_Is_Master_SLVSTART(port); + } + + for (port = I3C1_IF; port < I3C_PORT_MAX; port++) { + if (Get_Bus_From_Port(port) == pBus) { + return hal_I3C_Is_Slave_SLVSTART(port); + } + } + + return FALSE; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief validate bus is waiting for the STOP or RESTART ? + * @param [in] pBus bus object + * @return true, if bus is waiting for the STOP or RESTART + */ +/*------------------------------------------------------------------------------*/ +_Bool I3C_IS_BUS_WAIT_STOP_OR_RETRY(I3C_BUS_INFO_t *pBus) +{ + I3C_PORT_Enum port; + I3C_DEVICE_INFO_t *pDevice; + + if (pBus == NULL) { + return FALSE; + } + + if (pBus->pCurrentMaster != NULL) { + pDevice = pBus->pCurrentMaster; + port = pDevice->port; + return hal_I3C_Is_Master_NORMAL(port); + } + + return FALSE; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Create a simplified device info to describe device in the bus + * @param [in] pBus The bus the device belongs to + * @param [in] pDevice pointer to the device object + * @param [in] attr describe the device is present or not and how to initialize + * @param [in] prefferedAddr Used to define the preferred dynamic address for I3C, or + * static address for I2C + * @param [in] dynamicAddr Used to record the dynamic address of the device + * @param [in] pid pid of the device object + * @param [in] bcr bcr of the device object + * @param [in] dcr dcr of the device object + * @return pointer to the simplified device info + */ +/*------------------------------------------------------------------------------*/ +I3C_DEVICE_INFO_SHORT_t *NewDevInfo(I3C_BUS_INFO_t *pBus, void *pDevice, I3C_DEVICE_ATTRIB_t attr, + __u8 prefferedAddr, __u8 dynamicAddr, __u8 pid[], __u8 bcr, __u8 dcr) +{ + I3C_DEVICE_INFO_SHORT_t *pNewDev; + I3C_DEVICE_INFO_SHORT_t *pThisDev; + + if (pBus == NULL) { + return NULL; + } + + if (pDevice == NULL) { + return NULL; + } + + pNewDev = (I3C_DEVICE_INFO_SHORT_t *)hal_I3C_MemAlloc(sizeof(I3C_DEVICE_INFO_SHORT_t)); + if (pNewDev == NULL) { + return NULL; + } + + pNewDev->pDeviceInfo = pDevice; + pNewDev->attr = attr; + pNewDev->dynamicAddr = dynamicAddr; + memcpy(pNewDev->pid, pid, 6); + pNewDev->bcr = bcr; + pNewDev->dcr = dcr; + pNewDev->staticAddr = prefferedAddr; + pNewDev->pNextDev = NULL; + + if (pBus->DevCount == 0) { + pBus->pDevList = pNewDev; + pBus->DevCount = 1; + return pNewDev; + } + + pThisDev = pBus->pDevList; + while (pThisDev->pNextDev != NULL) { + pThisDev = pThisDev->pNextDev; + } + + pThisDev->pNextDev = pNewDev; + pBus->DevCount++; + return pNewDev; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Get the device info from the bus + * @param [in] pBus pointer to the bus object + * @param [in] slaveAddr static address of the device object + * @return Return device info with specified static address + */ +/*------------------------------------------------------------------------------*/ +I3C_DEVICE_INFO_SHORT_t *GetDevInfoByStaticAddr(I3C_BUS_INFO_t *pBus, __u8 slaveAddr) +{ + I3C_DEVICE_INFO_SHORT_t *pDev; + + if (pBus == NULL) { + return NULL; + } + + pDev = pBus->pDevList; + while (pDev != NULL) { + if (pDev->staticAddr == slaveAddr) { + return pDev; + } + + pDev = pDev->pNextDev; + } + + return NULL; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Get the device info from the bus + * @param [in] pBus pointer to the bus object + * @param [in] slaveAddr dynamic address of the device object + * @return Return device info with specified dynamic address + */ +/*------------------------------------------------------------------------------*/ +I3C_DEVICE_INFO_SHORT_t *GetDevInfoByDynamicAddr(I3C_BUS_INFO_t *pBus, __u8 slaveAddr) +{ + I3C_DEVICE_INFO_SHORT_t *pDev; + + if (pBus == NULL) { + return NULL; + } + + pDev = pBus->pDevList; + while (pDev != NULL) { + if (pDev->dynamicAddr == slaveAddr) { + return pDev; + } + + pDev = pDev->pNextDev; + } + + return NULL; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Get the device info from the bus with specified slave task + * @param [in] pBus pointer to the bus object + * @param [in] pTask task + * @return Return device info with specified task + */ +/*------------------------------------------------------------------------------*/ +I3C_DEVICE_INFO_SHORT_t *GetDevInfoByTask(I3C_BUS_INFO_t *pBus, I3C_TRANSFER_TASK_t *pTask) +{ + I3C_PORT_Enum port; + I3C_DEVICE_INFO_t *pDevice; + I3C_TRANSFER_TASK_t *pThisTask; + + if (pBus == NULL) { + return NULL; + } + + if (pTask == NULL) { + return NULL; + } + + for (port = I3C1_IF; port < I3C_PORT_MAX; port++) { + pDevice = &gI3c_dev_node_internal[port]; + + if (pDevice->pOwner != pBus) { + continue; + } + + if (pDevice->mode == I3C_DEVICE_MODE_DISABLE) { + continue; + } + + if (pDevice->mode == I3C_DEVICE_MODE_CURRENT_MASTER) { + continue; + } + + pThisTask = pDevice->pTaskListHead; + while (pThisTask != NULL) { + if (pThisTask == pTask) { + return pDevice->pDevInfo; + } + + pThisTask = pThisTask->pNextTask; + } + } + + return NULL; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Used to check the device is internal device or not + * @param [in] pDevice pointer to the device object + * @return TRUE, if the device is an internal device + */ +/*------------------------------------------------------------------------------*/ +_Bool IS_Internal_DEVICE(void *pDevice) +{ + I3C_PORT_Enum port; + + for (port = I3C1_IF; port < I3C_PORT_MAX; port++) { + if (pDevice == &gI3c_dev_node_internal[port]) { + return TRUE; + } + } + + return FALSE; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Used to reset devices on the bus + * @param [in] pBus pointer to the bus object + * @return None + */ +/*------------------------------------------------------------------------------*/ +void I3C_Reset(__u8 busNo) +{ + I3C_BUS_INFO_t *pBus = NULL; + I3C_DEVICE_INFO_t *pDevice; + I3C_DEVICE_INFO_SHORT_t *pDev = NULL; + I3C_DEVICE_INFO_SHORT_t *pRemoveDev; + I3C_TRANSFER_TASK_t *pTask; + + pBus = &gBus[busNo]; + pDev = pBus->pDevList; + pBus->busState = I3C_BUS_STATE_WAIT_RESET_DONE; + + while (pDev != NULL) { + pRemoveDev = pDev; + + if (IS_Internal_DEVICE(pDev->pDeviceInfo)) { + pDevice = pDev->pDeviceInfo; + + while (pDevice->task_count) { + if (pDevice->pTaskListHead == NULL) { + break; + } + + pTask = pDevice->pTaskListHead; + I3C_Complete_Task(pTask->pTaskInfo); + }; + + /* used to disable I3C */ + pDevice->mode = I3C_DEVICE_MODE_DISABLE; + pDevice->callback = NULL; + pDevice->pOwner = NULL; + pDevice->pDevInfo = NULL; + hal_I3C_Config_Device(pDevice); + } + + /* clear devices info on the bus */ + pDev = pDev->pNextDev; + RemoveDevInfo(pBus, pRemoveDev); + } + + pBus->pCurrentTask = NULL; + pBus->pCurrentMaster = NULL; + pBus->busState = I3C_BUS_STATE_DEFAULT; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Remove a specific device info from the bus + * @param [in] pBus The bus the device belongs to + * @param [in] pDevInfo Specify what should be removed + * @return None + */ +/*------------------------------------------------------------------------------*/ +void RemoveDevInfo(I3C_BUS_INFO_t *pBus, I3C_DEVICE_INFO_SHORT_t *pDevInfo) +{ + I3C_DEVICE_INFO_SHORT_t *pThisDev; + I3C_DEVICE_INFO_SHORT_t *pPrevDev; + + if (pBus == NULL) { + return; + } + + if (pDevInfo == NULL) { + return; + } + + if (pBus->DevCount == 0) { + return; + } + + if (pBus->pDevList == NULL) { + return; + } + + pThisDev = pBus->pDevList; + if (pThisDev == pDevInfo) { + pBus->pDevList = pThisDev->pNextDev; + hal_I3C_MemFree(pThisDev); + pBus->DevCount--; + return; + } + + while (pThisDev->pNextDev != NULL) { + pPrevDev = pThisDev; + pThisDev = pPrevDev->pNextDev; + + if (pThisDev == pDevInfo) { + pPrevDev->pNextDev = pThisDev->pNextDev; + hal_I3C_MemFree(pThisDev); + pBus->DevCount--; + return; + } + } +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Reset a specific device info from the bus + * @param [in] pBus The bus the device belongs to + * @param [in] pDevInfo Specify what should be removed + * @return None + */ +/*------------------------------------------------------------------------------*/ +void ResetDevInfo(I3C_BUS_INFO_t *pBus, I3C_DEVICE_INFO_SHORT_t *pDevInfo) +{ + I3C_DEVICE_INFO_SHORT_t *pThisDev; + + if (pBus == NULL) { + return; + } + + if (pDevInfo == NULL) { + return; + } + + if (pBus->DevCount == 0) { + return; + } + + if (pBus->pDevList == NULL) { + return; + } + + pThisDev = pBus->pDevList; + if (pThisDev == pDevInfo) { + pThisDev->dynamicAddr = I3C_DYNAMIC_ADDR_DEFAULT_7BIT; + return; + } + + while (pThisDev->pNextDev != NULL) { + pThisDev = pThisDev->pNextDev; + + if (pThisDev == pDevInfo) { + pThisDev->dynamicAddr = I3C_DYNAMIC_ADDR_DEFAULT_7BIT; + return; + } + } +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Any device in the bus running in I3C mode ? + * @param [in] pBus bus object + * @return TRUE, if at least one slave device works in I3C mode + */ +/*------------------------------------------------------------------------------*/ +_Bool IS_I3C_DEVICE_PRESENT(I3C_BUS_INFO_t *pBus) +{ + I3C_DEVICE_INFO_t *pDevice; + I3C_DEVICE_INFO_SHORT_t *pDev; + + if (pBus == NULL) { + return FALSE; + } + + pDev = pBus->pDevList; + while (pDev != NULL) { + if (IS_Internal_DEVICE(pDev->pDeviceInfo)) { + pDevice = (I3C_DEVICE_INFO_t *)pDev->pDeviceInfo; + if (pDevice->bRunI3C) { + return TRUE; + } + } + + pDev = pDev->pNextDev; + } + + return FALSE; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Used to check device in the bus needs to do RSTDAA + * @param [in] pBus bus object + * @return TRUE, if at least one device need to do RSTDAA + */ +/*------------------------------------------------------------------------------*/ +_Bool IS_RSTDAA_DEVICE_PRESENT(I3C_BUS_INFO_t *pBus) +{ + I3C_DEVICE_INFO_SHORT_t *pDev; + + if (pBus == NULL) { + return FALSE; + } + + pDev = pBus->pDevList; + while (pDev != NULL) { + if ((pDev->attr.b.present) && (pDev->attr.b.reqRSTDAA) && + (pDev->attr.b.doneRSTDAA == 0)) { + return TRUE; + } + + pDev = pDev->pNextDev; + } + + return FALSE; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Used to check device in the bus needs to do SETHID + * @param [in] pBus bus object + * @return TRUE, if at least one device need to do SETHID + */ +/*------------------------------------------------------------------------------*/ +_Bool IS_SETHID_DEVICE_PRESENT(I3C_BUS_INFO_t *pBus) +{ + I3C_DEVICE_INFO_SHORT_t *pDev; + + if (pBus == NULL) { + return FALSE; + } + + pDev = pBus->pDevList; + while (pDev != NULL) { + if ((pDev->attr.b.present) && (pDev->attr.b.reqSETHID) && + (pDev->attr.b.doneSETHID == 0)) { + return TRUE; + } + + pDev = pDev->pNextDev; + } + + return FALSE; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Used to check device in the bus needs to do SETDASA + * @param [in] pBus bus object + * @return TRUE, if at least one device need to do SETDASA + */ +/*------------------------------------------------------------------------------*/ +_Bool IS_SETDASA_DEVICE_PRESENT(I3C_BUS_INFO_t *pBus) +{ + I3C_DEVICE_INFO_SHORT_t *pDev; + + if (pBus == NULL) { + return FALSE; + } + + pDev = pBus->pDevList; + while (pDev != NULL) { + if ((pDev->attr.b.present) && (pDev->attr.b.reqSETDASA) && + (pDev->attr.b.doneSETDASA == 0)) { + return TRUE; + } + + pDev = pDev->pNextDev; + } + + return FALSE; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Used to check device in the bus needs to do SETAASA + * @param [in] pBus bus object + * @return TRUE, if at least one device need to do SETAASA + */ +/*------------------------------------------------------------------------------*/ +_Bool IS_SETAASA_DEVICE_PRESENT(I3C_BUS_INFO_t *pBus) +{ + I3C_DEVICE_INFO_SHORT_t *pDev; + + if (pBus == NULL) { + return FALSE; + } + + pDev = pBus->pDevList; + while (pDev != NULL) { + if ((pDev->attr.b.present) && (pDev->attr.b.reqSETAASA) && + (pDev->attr.b.doneSETAASA == 0)) { + return TRUE; + } + + pDev = pDev->pNextDev; + } + + return FALSE; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Create brocast ENEC task + * @param [in] pBus bus object + * @param [in] mask enable setting + * @param [in] policy task insertion policy + * @return none + */ +/*------------------------------------------------------------------------------*/ +void I3C_CCCb_ENEC(I3C_BUS_INFO_t *pBus, __u8 mask, I3C_TASK_POLICY_Enum policy) +{ + I3C_DEVICE_INFO_t *pDevice; + __u16 TxLen; + __u8 TxBuf[1]; + + if (pBus == NULL) { + return; + } + + if (mask == 0) { + return; + } + + pDevice = pBus->pCurrentMaster; + if (pDevice == NULL) { + return; + } + + TxLen = 1; + TxBuf[0] = mask; + I3C_Master_Insert_Task_CCCb(CCC_BROADCAST_ENEC, TxLen, TxBuf, I3C_TRANSFER_SPEED_SDR_1MHZ, + TIMEOUT_TYPICAL, I3C_Master_Callback, pDevice->port, policy, NOT_HIF); +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Create brocast DISEC task + * @param [in] pBus bus object + * @param [in] mask disable setting + * @param [in] policy task insertion policy + * @return none + */ +/*------------------------------------------------------------------------------*/ +void I3C_CCCb_DISEC(I3C_BUS_INFO_t *pBus, __u8 mask, I3C_TASK_POLICY_Enum policy) +{ + I3C_DEVICE_INFO_t *pDevice; + __u16 TxLen; + __u8 TxBuf[1]; + + if (pBus == NULL) { + return; + } + + if (pBus->pCurrentMaster == NULL) { + return; + } + + if (mask == 0) { + return; + } + + + pDevice = pBus->pCurrentMaster; + TxLen = 1; + TxBuf[0] = mask; + I3C_Master_Insert_Task_CCCb(CCC_BROADCAST_DISEC, TxLen, TxBuf, I3C_TRANSFER_SPEED_SDR_1MHZ, + TIMEOUT_TYPICAL, I3C_Master_Callback, pDevice->port, policy, NOT_HIF); +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Create brocast RSTDAA task + * @param [in] pBus bus object + * @return none + */ +/*------------------------------------------------------------------------------*/ +void I3C_CCCb_RSTDAA(I3C_BUS_INFO_t *pBus) +{ + I3C_DEVICE_INFO_t *pDevice; + I3C_DEVICE_INFO_SHORT_t *pDev; + + if (pBus == NULL) { + return; + } + + if (pBus->pCurrentMaster == NULL) { + return; + } + + pDevice = pBus->pCurrentMaster; + pDev = pBus->pDevList; + while (pDev != NULL) { + if ((pDev->attr.b.present) && (pDev->attr.b.reqRSTDAA) && + (pDev->attr.b.doneRSTDAA == 0)) { + I3C_Master_Insert_Task_CCCb(CCC_BROADCAST_RSTDAA, 0, NULL, + I3C_TRANSFER_SPEED_SDR_1MHZ, TIMEOUT_TYPICAL, I3C_Master_Callback, + pDevice->port, I3C_TASK_POLICY_APPEND_LAST, NOT_HIF); + return; + } + + pDev = pDev->pNextDev; + } +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Create brocast ENTDAA task + * @param [in] pBus bus object + * @return none + */ +/*------------------------------------------------------------------------------*/ +void I3C_CCCb_ENTDAA(I3C_BUS_INFO_t *pBus) +{ + I3C_DEVICE_INFO_t *pDevice; + + if (pBus == NULL) { + return; + } + + if (pBus->pCurrentMaster == NULL) { + return; + } + + pDevice = pBus->pCurrentMaster; + I3C_Master_Insert_Task_ENTDAA(63, NULL, I3C_TRANSFER_SPEED_I2C_1MHZ, TIMEOUT_TYPICAL, + I3C_Master_Callback, pDevice->port, I3C_TASK_POLICY_APPEND_LAST, NOT_HIF); +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Create brocast SETAASA task + * @param [in] pBus bus object + * @return none + */ +/*------------------------------------------------------------------------------*/ +void I3C_CCCb_SETAASA(I3C_BUS_INFO_t *pBus) +{ + I3C_DEVICE_INFO_t *pDevice; + I3C_DEVICE_INFO_SHORT_t *pDev; + _Bool bNeedSETAASA; + + if (pBus == NULL) { + return; + } + + if (pBus->pCurrentMaster == NULL) { + return; + } + + pDevice = pBus->pCurrentMaster; + pDev = pBus->pDevList; + + bNeedSETAASA = FALSE; + while ((pDev != NULL) && (bNeedSETAASA == FALSE)) { + if ((pDev->attr.b.present) && (pDev->attr.b.reqSETAASA) && + (pDev->attr.b.doneSETAASA == 0)) { + bNeedSETAASA = TRUE; + } + + pDev = pDev->pNextDev; + } + + if (bNeedSETAASA) { + I3C_Master_Insert_Task_CCCb(CCC_BROADCAST_SETAASA, 0, NULL, + I3C_TRANSFER_SPEED_SDR_1MHZ, TIMEOUT_TYPICAL, I3C_Master_Callback, + pDevice->port, I3C_TASK_POLICY_APPEND_LAST, NOT_HIF); + } +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Create brocast SETHID task + * @param [in] pBus bus object + * @return none + */ +/*------------------------------------------------------------------------------*/ +void I3C_CCCb_SETHID(I3C_BUS_INFO_t *pBus) +{ + I3C_DEVICE_INFO_SHORT_t *pDev; + + if (pBus == NULL) { + return; + } + + pDev = pBus->pDevList; + while (pDev != NULL) { + if ((pDev->attr.b.present) && (pDev->attr.b.reqSETHID) && + (pDev->attr.b.doneSETHID == 0)) { + } + + pDev = pDev->pNextDev; + } +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Create direct ENEC task + * @param [in] pBus bus object + * @param [in] addr target device + * @param [in] mask enable setting + * @param [in] policy task insertion policy + * @return none + */ +/*------------------------------------------------------------------------------*/ +void I3C_CCCw_ENEC(I3C_BUS_INFO_t *pBus, __u8 addr, __u8 mask, I3C_TASK_POLICY_Enum policy) +{ + I3C_DEVICE_INFO_t *pDevice; + __u16 TxLen; + __u8 TxBuf[2]; + + if (pBus == NULL) { + return; + } + + if (pBus->pCurrentMaster == NULL) { + return; + } + + pDevice = pBus->pCurrentMaster; + + TxLen = 2; + TxBuf[0] = addr; + TxBuf[1] = mask; + I3C_Master_Insert_Task_CCCw(CCC_DIRECT_ENEC, 1, TxLen, TxBuf, I3C_TRANSFER_SPEED_SDR_1MHZ, + TIMEOUT_TYPICAL, I3C_Master_Callback, pDevice->port, policy, NOT_HIF); +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Create direct DISEC task + * @param [in] pBus bus object + * @param [in] addr target device + * @param [in] mask disable setting + * @param [in] policy task insertion policy + * @return none + */ +/*------------------------------------------------------------------------------*/ +void I3C_CCCw_DISEC(I3C_BUS_INFO_t *pBus, __u8 addr, __u8 mask, I3C_TASK_POLICY_Enum policy) +{ + I3C_DEVICE_INFO_t *pDevice; + __u16 TxLen; + __u8 TxBuf[2]; + + if (pBus == NULL) { + return; + } + + if (pBus->pCurrentMaster == NULL) { + return; + } + + pDevice = pBus->pCurrentMaster; + + TxLen = 2; + TxBuf[0] = addr; + TxBuf[1] = mask; + I3C_Master_Insert_Task_CCCw(CCC_DIRECT_DISEC, 1, TxLen, TxBuf, I3C_TRANSFER_SPEED_SDR_1MHZ, + TIMEOUT_TYPICAL, I3C_Master_Callback, pDevice->port, policy, NOT_HIF); +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Create direct SETDASA task + * @param [in] pBus bus object + * @return none + */ +/*------------------------------------------------------------------------------*/ +void I3C_CCCw_SETDASA(I3C_BUS_INFO_t *pBus) +{ + I3C_DEVICE_INFO_t *pDevice; + I3C_DEVICE_INFO_SHORT_t *pDev; + __u8 devCnt; + __u8 TxBuf[62]; + __u16 TxLen; + + if (pBus == NULL) { + return; + } + + if (pBus->pCurrentMaster == NULL) { + return; + } + + pDevice = pBus->pCurrentMaster; + pDev = pBus->pDevList; + + devCnt = 0; + while (pDev != NULL) { + if ((pDev->attr.b.present) && (pDev->attr.b.reqSETDASA) && + (pDev->attr.b.doneSETDASA == 0)) { + TxBuf[devCnt * 2 + 0] = pDev->staticAddr; + TxBuf[devCnt * 2 + 1] = (pDev->staticAddr << 1); + devCnt++; + + if (devCnt >= 31) { + break; + } + } + + pDev = pDev->pNextDev; + } + + if (devCnt) { + TxLen = 2 * devCnt; + I3C_Master_Insert_Task_CCCw(CCC_DIRECT_SETDASA, 1, TxLen, TxBuf, + I3C_TRANSFER_SPEED_SDR_1MHZ, TIMEOUT_TYPICAL, I3C_Master_Callback, + pDevice->port, I3C_TASK_POLICY_APPEND_LAST, NOT_HIF); + } +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Create direct SETNEWDA task + * @param [in] pBus bus object + * @param [in] dyn_addr_old old address + * @param [in] dyn_addr_new new address + * @return none + */ +/*------------------------------------------------------------------------------*/ +void I3C_CCCw_SETNEWDA(I3C_BUS_INFO_t *pBus, __u8 dyn_addr_old, __u8 dyn_addr_new) +{ + I3C_DEVICE_INFO_SHORT_t *pDev; + __u16 TxLen; + __u8 TxBuf[2]; + + if (pBus == NULL) { + return; + } + + pDev = pBus->pDevList; + while (1) { + if (pDev == NULL) { + return; + } + + if (pDev->dynamicAddr == dyn_addr_old) { + break; + } + + pDev = pDev->pNextDev; + } + + TxLen = 2; + TxBuf[0] = dyn_addr_old; + TxBuf[1] = dyn_addr_new << 1; + I3C_Master_Insert_Task_CCCw(CCC_DIRECT_SETNEWDA, 1, TxLen, TxBuf, + I3C_TRANSFER_SPEED_SDR_1MHZ, TIMEOUT_TYPICAL, I3C_Master_Callback, + pBus->pCurrentMaster->port, I3C_TASK_POLICY_APPEND_LAST, NOT_HIF); +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Inform slave device while task is complete or end with error + * @param [in] pTaskInfo Pointer to the running task + * @return task result + */ +/*------------------------------------------------------------------------------*/ +__u32 I3C_Notify(I3C_TASK_INFO_t *pTaskInfo) +{ + I3C_TRANSFER_TASK_t *pTask; + I3C_TRANSFER_PROTOCOL_Enum protocol; + I3C_DEVICE_INFO_t *pDevice; + I3C_BUS_INFO_t *pBus; + __u32 ret; + I3C_DEVICE_INFO_SHORT_t *pDev; + I3C_TRANSFER_FRAME_t *pThisFrame; + + __u8 i; + + if (pTaskInfo == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + + pTask = pTaskInfo->pTask; + protocol = pTask->protocol; + pDevice = &gI3c_dev_node_internal[pTaskInfo->Port]; + pBus = pDevice->pOwner; + ret = I3C_ERR_OK; + + /* Find slave to be notified */ + /* IBINACKed by master, only internal device */ + if (pTaskInfo->result == I3C_ERR_NACK_SLVSTART) { + pDev = GetDevInfoByTask(pBus, pTask); + pDevice = (I3C_DEVICE_INFO_t *)pDev->pDeviceInfo; + if (pDevice->callback != NULL) { + ret = pDevice->callback((__u32)pTaskInfo, pTaskInfo->result); + return ret; + } + } + + if (protocol == I3C_TRANSFER_PROTOCOL_HOT_JOIN) { + return pTaskInfo->result; + } + + if (protocol == I3C_TRANSFER_PROTOCOL_IBI) { + /* IBIACKed by master */ + pDev = GetDevInfoByTask(pBus, pTask); + pDevice = (I3C_DEVICE_INFO_t *)pDev->pDeviceInfo; + if (pDevice->callback != NULL) { + ret = pDevice->callback((__u32)pTaskInfo, pTaskInfo->result); + return ret; + } + } + + if (protocol == I3C_TRANSFER_PROTOCOL_MASTER_REQUEST) { + /* 1. IBINACKed by master ? */ + /* 2. slave request with higher priority ? */ + pDev = GetDevInfoByTask(pBus, pTask); + pDevice = (I3C_DEVICE_INFO_t *)pDev->pDeviceInfo; + if (pDevice->callback != NULL) { + ret = pDevice->callback((__u32)pTaskInfo, pTaskInfo->result); + return ret; + } + } + + /* Master Task */ + for (i = pTask->frame_idx; i < pTask->frame_count; i++) { + pThisFrame = &pTask->pFrameList[i]; + + if ((pTask->protocol == I3C_TRANSFER_PROTOCOL_CCCb) && (i == 0)) { + /* + * SLVSTART: CCCb + * SETHID / SETAASA / DEVCTRL + */ + continue; + } + + if (pThisFrame->address == I3C_BROADCAST_ADDR) { + continue; + } + + /* specific address */ + if (pThisFrame->type == I3C_TRANSFER_TYPE_I2C) { + pDev = GetDevInfoByStaticAddr(pBus, pThisFrame->address); + } else { + pDev = GetDevInfoByDynamicAddr(pBus, pThisFrame->address); + } + + if (pDev == NULL) { + continue; + } + } + + return ret; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Create master task + * @param[in] Protocol Traffic format + * @param[in] Addr specify target address for non-CCC traffic, + * For CCCb, it describes the data length including + * CCC + Write data + [PEC] + * For CCCw, it describes the data length including + * Target Address + Write data + [PEC], for each target + * For CCCr, it describes the data length including + * Target Address + read data + [PEC], for each target + * @param[in] HSize Used to specify the data length of the first frame + * @param[in] pWrCnt Used to specify write data length + * @param[in] pRdCnt Used to specify read data length + * @param[in] WrBuf Used to specify write data buffer + * @param[in] RdBuf Used to specify read data buffer + * @param[in] Baudrate Used to specify baudrate + * @param[in] Timeout Used to specify timeout (unit: 10ms) + * @param[in] callback Used to handle task result + * @param[in] PortId perform task in which i3c port + * @param[in] Policy task insert policy, insert in the head for the urgent + * case (event), tail for normal case + * @param[in] bHIF 0b, memory allocated in the callee, free data buffer + * if task is finished + * 1b, memory allocated in the caller, should not free + * data buffer even if task is finished + * @return allocated task info if it is not NULL + */ +/*------------------------------------------------------------------------------*/ +I3C_TASK_INFO_t *I3C_Master_Create_Task(I3C_TRANSFER_PROTOCOL_Enum Protocol, + __u8 Addr, __u8 HSize, __u16 *pWrCnt, __u16 *pRdCnt, __u8 *WrBuf, __u8 *RdBuf, + __u32 Baudrate, __u32 Timeout, ptrI3C_RetFunc callback, + __u8 PortId, I3C_TASK_POLICY_Enum Policy, _Bool bHIF) +{ + I3C_DEVICE_INFO_t *pDevice; + I3C_TASK_INFO_t *pTaskInfo; + + if (PortId >= I3C_PORT_MAX) { + return NULL; + } + + pDevice = &gI3c_dev_node_internal[PortId]; + if (pDevice->task_count >= I3C_TASK_MAX) { + return NULL; + } + + pTaskInfo = (I3C_TASK_INFO_t *)NewTaskInfo(); + if (pTaskInfo == NULL) { + return NULL; + } + + InitTaskInfo(pTaskInfo); + + if (ValidateProtocol(Protocol) != I3C_ERR_OK) { + hal_I3C_MemFree(pTaskInfo); + return NULL; + } + + if (ValidateBaudrate(Protocol, Baudrate) != I3C_ERR_OK) { + hal_I3C_MemFree(pTaskInfo); + return NULL; + } + + if (ValidateBuffer(Protocol, Addr, HSize, *pWrCnt, *pRdCnt, WrBuf, RdBuf, bHIF) != + I3C_ERR_OK) { + hal_I3C_MemFree(pTaskInfo); + return NULL; + } + + if (CreateTaskNode(pTaskInfo, Protocol, Baudrate, Addr, HSize, pWrCnt, WrBuf, pRdCnt, + RdBuf, callback, bHIF) != I3C_ERR_OK) { + hal_I3C_MemFree(pTaskInfo); + return NULL; + } + + pTaskInfo->MasterRequest = TRUE; + pTaskInfo->Port = PortId; + pTaskInfo->u32SwTimeout = Timeout; + + /* Later, I3C Task Engine will pick it from device's task list */ + InsertTaskNode(pDevice, pTaskInfo->pTask, Policy); + + pDevice->task_count++; + pTaskInfo->result = I3C_ERR_PENDING; + return pTaskInfo; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Create slave task + * @param[in] Protocol Traffic format + * @param[in] Addr specify data length return for IBI, + * @param[in] pWrCnt Used to specify write data length + * @param[in] pRdCnt Used to specify read data length + * @param[in] WrBuf Used to specify write data buffer + * @param[in] RdBuf Used to specify read data buffer + * @param[in] Timeout Used to specify timeout (unit: 10ms) + * @param[in] callback Used to handle task result + * @param[in] PortId perform task in which i3c port + * @param[in] bHIF 0b, memory allocated in the callee, + * free data buffer if task is finished + * 1b, memory allocated in the caller, + * should not free data buffer even if task is finished + * @return allocated task info if it is not NULL + */ +/*------------------------------------------------------------------------------*/ +I3C_TASK_INFO_t *I3C_Slave_Create_Task(I3C_TRANSFER_PROTOCOL_Enum Protocol, + __u8 Addr, __u16 *pWrCnt, __u16 *pRdCnt, __u8 *WrBuf, __u8 *RdBuf, + __u32 Timeout, ptrI3C_RetFunc callback, __u8 PortId, _Bool bHIF) +{ + I3C_DEVICE_INFO_t *pDevice; + I3C_TASK_INFO_t *pTaskInfo; + + if (PortId >= I3C_PORT_MAX) { + return NULL; + } + + pDevice = &gI3c_dev_node_internal[PortId]; + if (pDevice->task_count > I3C_TASK_MAX) { + return NULL; + } + + pTaskInfo = NewTaskInfo(); + if (pTaskInfo == NULL) { + return NULL; + } + + InitTaskInfo(pTaskInfo); + + if ((ValidateProtocol(Protocol) != I3C_ERR_OK) || + (ValidateBuffer(Protocol, Addr, 0, *pWrCnt, *pRdCnt, WrBuf, RdBuf, bHIF) != + I3C_ERR_OK) || + (CreateTaskNode(pTaskInfo, Protocol, pDevice->baudrate.i3cSdr, Addr, 0, pWrCnt, + WrBuf, 0, NULL, callback, bHIF) != I3C_ERR_OK)) { + hal_I3C_MemFree(pTaskInfo); + return NULL; + } + + pTaskInfo->MasterRequest = FALSE; + pTaskInfo->Port = PortId; + pTaskInfo->u32SwTimeout = Timeout; + + InsertTaskNode(pDevice, pTaskInfo->pTask, I3C_TASK_POLICY_APPEND_LAST); + + pDevice->task_count++; + pTaskInfo->result = I3C_ERR_PENDING; + return pTaskInfo; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Remove task from device's task list + * @param [in] pTaskInfo Specify removed task info + * @return None + */ +/*------------------------------------------------------------------------------*/ +void I3C_Complete_Task(I3C_TASK_INFO_t *pTaskInfo) +{ + I3C_DEVICE_INFO_t *pDevice; + I3C_TRANSFER_TASK_t *pTask; + I3C_TRANSFER_TASK_t *pParentTask; + + if (pTaskInfo == NULL) { + return; + } + + if (pTaskInfo->pTask == NULL) { + return; + } + + pTask = pTaskInfo->pTask; + pDevice = &gI3c_dev_node_internal[pTaskInfo->Port]; + + if (pDevice->pTaskListHead == NULL) { + return; + } + + if (pTask == pDevice->pTaskListHead) { + pDevice->pTaskListHead = pTask->pNextTask; + } else { + pParentTask = pDevice->pTaskListHead; + while (pParentTask != NULL) { + if (pParentTask->pNextTask == pTask) { + break; + } + + pParentTask = pParentTask->pNextTask; + } + + if ((pParentTask == NULL) || (pParentTask->pNextTask != pTask)) { + return; + } + + pParentTask->pNextTask = pTask->pNextTask; + } + + pDevice->task_count--; + FreeTaskNode(pTask); + + hal_I3C_MemFree(pTaskInfo); + pTaskInfo = NULL; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Free I3C tasks for a specific slave device + * @param [in] pDevice Pointer to the slave device + * @return TRUE + */ +/*------------------------------------------------------------------------------*/ +_Bool I3C_Clean_Slave_Task(I3C_DEVICE_INFO_t *pDevice) +{ + if (pDevice == NULL) { + return TRUE; + } + + while (pDevice->pTaskListHead != NULL) { + I3C_Complete_Task(pDevice->pTaskListHead->pTaskInfo); + } + + return TRUE; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Allocate memory to save task info + * @return pointer to the new task info + */ +/*------------------------------------------------------------------------------*/ +void *NewTaskInfo(void) +{ + I3C_TASK_INFO_t *pNewTaskInfo; + + pNewTaskInfo = (I3C_TASK_INFO_t *)hal_I3C_MemAlloc(sizeof(I3C_TASK_INFO_t)); + return pNewTaskInfo; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Set init value for task info + * @param [in] pTaskInfo pointer to the task info + * @return None + */ +/*------------------------------------------------------------------------------*/ +void InitTaskInfo(I3C_TASK_INFO_t *pTaskInfo) +{ + pTaskInfo->pTask = NULL; + pTaskInfo->result = I3C_ERR_OK; + pTaskInfo->MasterRequest = FALSE; + pTaskInfo->bHIF = FALSE; + pTaskInfo->Port = 0xFF; + pTaskInfo->u32SwTimeout = TIMEOUT_TYPICAL; + pTaskInfo->callback = NULL; + pTaskInfo->pParentTaskInfo = NULL; + + pTaskInfo->idx = 0; + pTaskInfo->fmt = 0; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Free mem for a specific task + * @param [in] pTask Pointer to the task + * @return None + */ +/*------------------------------------------------------------------------------*/ +void FreeTaskNode(I3C_TRANSFER_TASK_t *pTask) +{ + I3C_TASK_INFO_t *pTaskInfo; + + if (pTask == NULL) { + return; + } + + pTaskInfo = pTask->pTaskInfo; + if ((pTaskInfo != NULL) && (pTaskInfo->bHIF == FALSE)) { + if (pTask->pRdLen != NULL) { + hal_I3C_MemFree(pTask->pRdLen); + pTask->pRdLen = NULL; + } + + if (pTask->pRdBuf != NULL) { + hal_I3C_MemFree(pTask->pRdBuf); + pTask->pRdBuf = NULL; + } + } + + if (pTask->pWrLen != NULL) { + hal_I3C_MemFree(pTask->pWrLen); + pTask->pWrLen = NULL; + } + + if (pTask->pWrBuf != NULL) { + hal_I3C_MemFree(pTask->pWrBuf); + pTask->pWrBuf = NULL; + } + + if (pTask->pFrameList != NULL) { + hal_I3C_MemFree(pTask->pFrameList); + pTask->pFrameList = NULL; + } + + hal_I3C_MemFree(pTask); + pTask = NULL; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Validate for support protocol + * @param [in] Protocol Protocol + * @return I3C_ERR_OK, if the specified protocol is support + */ +/*------------------------------------------------------------------------------*/ +I3C_ErrCode_Enum ValidateProtocol(I3C_TRANSFER_PROTOCOL_Enum Protocol) +{ + /* slave task */ + if (Protocol == I3C_TRANSFER_PROTOCOL_IBI) { + return I3C_ERR_OK; + } + + if (Protocol == I3C_TRANSFER_PROTOCOL_MASTER_REQUEST) { + return I3C_ERR_OK; + } + + if (Protocol == I3C_TRANSFER_PROTOCOL_HOT_JOIN) { + return I3C_ERR_OK; + } + + /* master task */ + if ((Protocol >= I3C_TRANSFER_PROTOCOL_I2C_WRITE) && + (Protocol <= I3C_TRANSFER_PROTOCOL_I2C_WRITEnREAD)) { + return I3C_ERR_OK; + } + + if ((Protocol >= I3C_TRANSFER_PROTOCOL_I3C_WRITE) && + (Protocol <= I3C_TRANSFER_PROTOCOL_I3C_W7EnREAD)) { + return I3C_ERR_OK; + } + + if ((Protocol >= I3C_TRANSFER_PROTOCOL_DDR_WRITE) && + (Protocol <= I3C_TRANSFER_PROTOCOL_DDR_READ)) { + return I3C_ERR_OK; + } + + if ((Protocol >= I3C_TRANSFER_PROTOCOL_CCCb) && + (Protocol <= I3C_TRANSFER_PROTOCOL_CCCr)) { + return I3C_ERR_OK; + } + + if (Protocol == I3C_TRANSFER_PROTOCOL_ENTDAA) { + return I3C_ERR_OK; + } + + if (Protocol == I3C_TRANSFER_PROTOCOL_EVENT) { + return I3C_ERR_OK; + } + + return I3C_ERR_PARAMETER_INVALID; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Validate baudrate setting + * @param [in] Protocol Protocol + * @param [in] BaudRate Baudrate + * @return I3C_ERR_OK, if the specified baudrate is good + */ +/*------------------------------------------------------------------------------*/ +I3C_ErrCode_Enum ValidateBaudrate(I3C_TRANSFER_PROTOCOL_Enum Protocol, __u32 BaudRate) +{ + if (EVENT_TRANSFER_PROTOCOL(Protocol)) { + return I3C_ERR_OK; + } else if (I2C_TRANSFER_PROTOCOL(Protocol)) { + if (BaudRate == I3C_TRANSFER_SPEED_I2C_1MHZ) { + return I3C_ERR_OK; + } + + if (BaudRate == I3C_TRANSFER_SPEED_I2C_400KHZ) { + return I3C_ERR_OK; + } + + if (BaudRate == I3C_TRANSFER_SPEED_I2C_100KHZ) { + return I3C_ERR_OK; + } + } else if (I3C_TRANSFER_PROTOCOL(Protocol)) { + if (BaudRate == I3C_TRANSFER_SPEED_SDR_12p5MHZ) { + return I3C_ERR_OK; + } + + if (BaudRate == I3C_TRANSFER_SPEED_SDR_8MHZ) { + return I3C_ERR_OK; + } + + if (BaudRate == I3C_TRANSFER_SPEED_SDR_6MHZ) { + return I3C_ERR_OK; + } + + if (BaudRate == I3C_TRANSFER_SPEED_SDR_4MHZ) { + return I3C_ERR_OK; + } + + if (BaudRate == I3C_TRANSFER_SPEED_SDR_2MHZ) { + return I3C_ERR_OK; + } + + if (BaudRate == I3C_TRANSFER_SPEED_SDR_1MHZ) { + return I3C_ERR_OK; + } + } else { + if (BaudRate == I3C_TRANSFER_SPEED_I2C_1MHZ) { + return I3C_ERR_OK; + } + + if (BaudRate == I3C_TRANSFER_SPEED_I2C_400KHZ) { + return I3C_ERR_OK; + } + + if (BaudRate == I3C_TRANSFER_SPEED_SDR_12p5MHZ) { + return I3C_ERR_OK; + } + + if (BaudRate == I3C_TRANSFER_SPEED_SDR_8MHZ) { + return I3C_ERR_OK; + } + + if (BaudRate == I3C_TRANSFER_SPEED_SDR_6MHZ) { + return I3C_ERR_OK; + } + + if (BaudRate == I3C_TRANSFER_SPEED_SDR_4MHZ) { + return I3C_ERR_OK; + } + + if (BaudRate == I3C_TRANSFER_SPEED_SDR_2MHZ) { + return I3C_ERR_OK; + } + + if (BaudRate == I3C_TRANSFER_SPEED_SDR_1MHZ) { + return I3C_ERR_OK; + } + + if (BaudRate == I3C_TRANSFER_SPEED_SDR_IBI) { + return I3C_ERR_OK; + } + } + + return I3C_ERR_PARAMETER_INVALID; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Validate buffer + * @param [in] Protocol Protocol + * @param [in] Address Specify target address or data length for CCC + * @param [in] HSize Specify the data length for the first frame + * @param [in] WrCnt Specify the data length for the write buffer + * @param [in] RdCnt Specify the data length for the read buffer + * @param [in] WrBuf Specify the data buffer for the write buffer + * @param [in] RdBuf Specify the data buffer for the read buffer + * @param [in] bHIF task create via HIF ? + * @return I3C_ERR_OK, if the specified buffer and buffer count are good + */ +/*------------------------------------------------------------------------------*/ +I3C_ErrCode_Enum ValidateBuffer(I3C_TRANSFER_PROTOCOL_Enum Protocol, __u8 Address, + __u8 HSize, __u16 WrCnt, __u16 RdCnt, __u8 *WrBuf, __u8 *RdBuf, _Bool bHIF) +{ + if (DDR_TRANSFER_PROTOCOL(Protocol)) { + if (READ_TRANSFER_PROTOCOL(Protocol)) { + if (WrCnt < 1) { + return I3C_ERR_PARAMETER_INVALID; /* DDR_CMD */ + } + + if (WrBuf == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + + if ((WrBuf[0] & 0x80) == 0) { + return I3C_ERR_PARAMETER_INVALID; + } + + if (RdCnt == 0) { + return I3C_ERR_PARAMETER_INVALID; + } + } else { + if (WrCnt < 2) { + return I3C_ERR_PARAMETER_INVALID; /* DDR_CMD + DDR_DATA */ + } + + if (WrBuf == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + + if (WrBuf[0] & 0x80) { + return I3C_ERR_PARAMETER_INVALID; + } + } + } else if (CCC_TRANSFER_PROTOCOL(Protocol)) { + if (Protocol == I3C_TRANSFER_PROTOCOL_ENTDAA) { + if (WrCnt < 1) { + return I3C_ERR_PARAMETER_INVALID; + } + + if (WrBuf == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + + if (WrBuf[0] != CCC_BROADCAST_ENTDAA) { + return I3C_ERR_PARAMETER_INVALID; + } + + /* at least 9 bytes for 1 slave's info */ + if (RdCnt < 9) { + return I3C_ERR_PARAMETER_INVALID; + } + } else if (Protocol == I3C_TRANSFER_PROTOCOL_CCCr) { + if (WrCnt < 2) { + return I3C_ERR_PARAMETER_INVALID; /* CCC + 1 target address */ + } + + if (WrBuf == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + + if (CCC_BROADCAST(WrBuf[0])) { + return I3C_ERR_PARAMETER_INVALID; + } + } else if (Protocol == I3C_TRANSFER_PROTOCOL_CCCw) { + if (WrCnt < 2) { + return I3C_ERR_PARAMETER_INVALID; /* CCC + 1 target address */ + } + + if (WrBuf == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + + if (CCC_BROADCAST(WrBuf[0])) { + return I3C_ERR_PARAMETER_INVALID; + } + + if (((WrCnt - HSize) % Address) != 0) { + return I3C_ERR_PARAMETER_INVALID; + } + } else if (Protocol == I3C_TRANSFER_PROTOCOL_CCCb) { + if (WrCnt < 1) { + return I3C_ERR_PARAMETER_INVALID; /* CCC */ + } + + if (WrBuf == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + + if (!CCC_BROADCAST(WrBuf[0])) { + return I3C_ERR_PARAMETER_INVALID; + } + + if (WrCnt != HSize) { + return I3C_ERR_PARAMETER_INVALID; + } + } + } else if (Protocol == I3C_TRANSFER_PROTOCOL_I2C_WRITE) { + if ((WrCnt < 1) || (WrBuf == NULL)) { + return I3C_ERR_PARAMETER_INVALID; + } + } else if (Protocol == I3C_TRANSFER_PROTOCOL_I2C_READ) { + /* Although RdCnt could be 0 before message transfer, + * master should allocate enough space to restore the receiving data + */ + if (RdCnt == 0) { + return I3C_ERR_PARAMETER_INVALID; + } + } else if (Protocol == I3C_TRANSFER_PROTOCOL_I2C_WRITEnREAD) { + if ((WrCnt < 1) || (WrBuf == NULL) || (RdCnt == 0)) { + return I3C_ERR_PARAMETER_INVALID; + } + } else if ((Protocol == I3C_TRANSFER_PROTOCOL_I3C_WRITE) || + (Protocol == I3C_TRANSFER_PROTOCOL_I3C_W7E)) { + if ((WrCnt < 1) || (WrBuf == NULL)) { + return I3C_ERR_PARAMETER_INVALID; + } + } else if ((Protocol == I3C_TRANSFER_PROTOCOL_I3C_READ) || + (Protocol == I3C_TRANSFER_PROTOCOL_I3C_R7E)) { + if (RdCnt == 0) { + return I3C_ERR_PARAMETER_INVALID; + } + } else if ((Protocol == I3C_TRANSFER_PROTOCOL_I3C_WRITEnREAD) || + (Protocol == I3C_TRANSFER_PROTOCOL_I3C_W7EnREAD)) { + if ((WrCnt < 1) || (WrBuf == NULL) || (RdCnt == 0)) { + return I3C_ERR_PARAMETER_INVALID; + } + } + + return I3C_ERR_OK; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Create Task + * @param [in] pTaskInfo Specify task info + * @param [in] Protocol Protocol for a specific task + * @param [in] Baudrate Baudrate setting for a specific task + * @param [in] Addr target address + * @param [in] HSize Specify the data length for the first frame + * @param [in] pWrCnt Specify the data length for the write buffer + * @param [in] WrBuf Specify the write buffer + * @param [in] pRdCnt Specify the data length for the read buffer + * @param [in] RdBuf Specify the read buffer + * @param [in] callback Specify the callback function + * @param [in] bHIF data buffer will be free automatically ? + * @return I3C_ERR_OK, if the task create successfully + */ +/*------------------------------------------------------------------------------*/ +I3C_ErrCode_Enum CreateTaskNode(I3C_TASK_INFO_t *pTaskInfo, + I3C_TRANSFER_PROTOCOL_Enum Protocol, __u32 Baudrate, __u8 Addr, __u8 HSize, + __u16 *pWrCnt, __u8 *WrBuf, __u16 *pRdCnt, __u8 *RdBuf, ptrI3C_RetFunc callback, _Bool bHIF) +{ + __u16 i; + __u8 *pTxBuf = NULL; + __u8 *pRxBuf = NULL; + I3C_TRANSFER_FRAME_t *pFrameNode = NULL; + I3C_TRANSFER_TASK_t *pNewTask; + + /* build task and frame in according to input parameters */ + pNewTask = (I3C_TRANSFER_TASK_t *)hal_I3C_MemAlloc(sizeof(I3C_TRANSFER_TASK_t)); + if (pNewTask == NULL) { + return I3C_ERR_OUT_OF_MEMORY; + } + + if (bHIF) { + /* do not free rx data buffer */ + pRxBuf = RdBuf; + pNewTask->pRdBuf = RdBuf; + pNewTask->pRdLen = pRdCnt; + } else { + pNewTask->pRdLen = NULL; + pNewTask->pRdBuf = NULL; + + if ((pRdCnt != NULL) && (*pRdCnt != 0)) { + pNewTask->pRdLen = (__u16 *)hal_I3C_MemAlloc(1); + pRxBuf = (__u8 *)hal_I3C_MemAlloc(*pRdCnt); + + if ((pNewTask->pRdLen == NULL) || (pRxBuf == NULL)) { + FreeTaskNode(pNewTask); + return I3C_ERR_OUT_OF_MEMORY; + } + + pNewTask->pRdBuf = pRxBuf; + *pNewTask->pRdLen = *pRdCnt; + } + } + + /* we need to modify write buffer and write len, so we should always allocate memory */ + pNewTask->pWrBuf = NULL; + pNewTask->pWrLen = NULL; + + if ((pWrCnt != NULL) && (*pWrCnt != 0) && (WrBuf != NULL)) { + pNewTask->pWrLen = (__u16 *)hal_I3C_MemAlloc(1); + pTxBuf = (__u8 *)hal_I3C_MemAlloc(*pWrCnt); + + if ((pNewTask->pWrLen == NULL) || (pTxBuf == NULL)) { + FreeTaskNode(pNewTask); + return I3C_ERR_OUT_OF_MEMORY; + } + + pNewTask->pWrBuf = pTxBuf; + memcpy(pTxBuf, WrBuf, *pWrCnt); + *pNewTask->pWrLen = *pWrCnt; + } + + /* setup task content */ + /* retry used in i3c for slave power down, i3c read and interrupted by slave start */ + pNewTask->pFrameList = NULL; + pNewTask->frame_count = 0; + + if (CCC_TRANSFER_PROTOCOL(Protocol)) { + if (Protocol == I3C_TRANSFER_PROTOCOL_ENTDAA) { + /* PID[6] + BCR[1] + DCR[1] + ADDR[1] */ + pNewTask->frame_count = 1 + (*pRdCnt / 9); + pFrameNode = (I3C_TRANSFER_FRAME_t *) hal_I3C_MemAlloc( + sizeof(I3C_TRANSFER_FRAME_t) * pNewTask->frame_count); + + if (pFrameNode == NULL) { + FreeTaskNode(pNewTask); + return I3C_ERR_OUT_OF_MEMORY; + } + + pFrameNode[0].pOwner = pNewTask; + pFrameNode[0].flag = I3C_TRANSFER_NORMAL | I3C_TRANSFER_RETRY_ENABLE; + pFrameNode[0].type = I3C_TRANSFER_TYPE_SDR; + pFrameNode[0].baudrate = Baudrate; + pFrameNode[0].address = I3C_BROADCAST_ADDR; + pFrameNode[0].direction = I3C_TRANSFER_DIR_WRITE; + pFrameNode[0].access_len = *pWrCnt; + pFrameNode[0].access_idx = 0; + pFrameNode[0].access_buf = pTxBuf; + pFrameNode[0].retry_count = 0; + pFrameNode[0].pNextFrame = &pFrameNode[1]; + + i = 0; + while (1) { + pNewTask->frame_idx = 1 + i; + if (pNewTask->frame_idx == pNewTask->frame_count) { + break; + } + + /* Stop automatically for slave NAK or master stop */ + pFrameNode[pNewTask->frame_idx].flag = I3C_TRANSFER_NORMAL | + I3C_TRANSFER_REPEAT_START; + if (pNewTask->frame_idx == (pNewTask->frame_count - 1)) { + pFrameNode[pNewTask->frame_idx].pNextFrame = NULL; + } else { + pFrameNode[pNewTask->frame_idx].pNextFrame = + &pFrameNode[pNewTask->frame_idx + 1]; + } + + pFrameNode[pNewTask->frame_idx].pOwner = pNewTask; + pFrameNode[pNewTask->frame_idx].type = I3C_TRANSFER_TYPE_SDR; + pFrameNode[pNewTask->frame_idx].baudrate = Baudrate; + pFrameNode[pNewTask->frame_idx].address = I3C_BROADCAST_ADDR; + pFrameNode[pNewTask->frame_idx].direction = I3C_TRANSFER_DIR_WRITE; + pFrameNode[pNewTask->frame_idx].access_len = 8; + pFrameNode[pNewTask->frame_idx].access_idx = 0; + pFrameNode[pNewTask->frame_idx].access_buf = &pRxBuf[i * 9]; + + /* if slave nak or no slave ack, master should terminate ENTDAA */ + pFrameNode[pNewTask->frame_idx].retry_count = 0; + + i++; + } + } else if (Protocol == I3C_TRANSFER_PROTOCOL_CCCb) { + pNewTask->frame_count = 1; + pFrameNode = (I3C_TRANSFER_FRAME_t *)hal_I3C_MemAlloc( + sizeof(I3C_TRANSFER_FRAME_t) * pNewTask->frame_count); + + if (pFrameNode == NULL) { + FreeTaskNode(pNewTask); + return I3C_ERR_OUT_OF_MEMORY; + } + + pFrameNode[0].pOwner = pNewTask; + pFrameNode[0].flag = I3C_TRANSFER_NORMAL | I3C_TRANSFER_RETRY_ENABLE; + pFrameNode[0].type = I3C_TRANSFER_TYPE_SDR; + pFrameNode[0].baudrate = Baudrate; + pFrameNode[0].address = I3C_BROADCAST_ADDR; + pFrameNode[0].direction = I3C_TRANSFER_DIR_WRITE; + pFrameNode[0].access_len = HSize; + pFrameNode[0].access_idx = 0; + pFrameNode[0].access_buf = pTxBuf; + pFrameNode[0].retry_count = 3; + pFrameNode[0].pNextFrame = NULL; + } else if (Protocol == I3C_TRANSFER_PROTOCOL_CCCw) { + pNewTask->frame_count = 1 + ((*pWrCnt - HSize) / Addr); + pFrameNode = (I3C_TRANSFER_FRAME_t *)hal_I3C_MemAlloc( + sizeof(I3C_TRANSFER_FRAME_t) * pNewTask->frame_count); + + if (pFrameNode == NULL) { + FreeTaskNode(pNewTask); + return I3C_ERR_OUT_OF_MEMORY; + } + + pFrameNode[0].pOwner = pNewTask; + pFrameNode[0].flag = I3C_TRANSFER_NORMAL | I3C_TRANSFER_RETRY_ENABLE | + I3C_TRANSFER_NO_STOP; + pFrameNode[0].type = I3C_TRANSFER_TYPE_SDR; + pFrameNode[0].baudrate = Baudrate; + pFrameNode[0].address = I3C_BROADCAST_ADDR; + pFrameNode[0].direction = I3C_TRANSFER_DIR_WRITE; + pFrameNode[0].access_len = HSize; + pFrameNode[0].access_idx = 0; + pFrameNode[0].access_buf = pTxBuf; + pFrameNode[0].retry_count = 3; + pFrameNode[0].pNextFrame = &pFrameNode[1]; + + i = 0; + while (1) { + pNewTask->frame_idx = 1 + i; + if (pNewTask->frame_idx == pNewTask->frame_count) { + break; + } + + if (pNewTask->frame_idx == (pNewTask->frame_count - 1)) { + pFrameNode[pNewTask->frame_idx].flag = I3C_TRANSFER_NORMAL | + I3C_TRANSFER_REPEAT_START; + pFrameNode[pNewTask->frame_idx].pNextFrame = NULL; + } else { + pFrameNode[pNewTask->frame_idx].flag = I3C_TRANSFER_NORMAL | + I3C_TRANSFER_REPEAT_START | I3C_TRANSFER_NO_STOP; + pFrameNode[pNewTask->frame_idx].pNextFrame = + &pFrameNode[pNewTask->frame_idx + 1]; + } + + pFrameNode[pNewTask->frame_idx].pOwner = pNewTask; + pFrameNode[pNewTask->frame_idx].type = I3C_TRANSFER_TYPE_SDR; + pFrameNode[pNewTask->frame_idx].baudrate = Baudrate; + + /* addr = WrBuf[HSize + i * Format] */ + pFrameNode[pNewTask->frame_idx].address = pTxBuf[HSize + i * Addr]; + pFrameNode[pNewTask->frame_idx].direction = I3C_TRANSFER_DIR_WRITE; + pFrameNode[pNewTask->frame_idx].access_len = Addr - 1; + pFrameNode[pNewTask->frame_idx].access_idx = 0; + + if (Addr == 1) { + /* address only, no optional write data */ + pFrameNode[pNewTask->frame_idx].access_buf = NULL; + } else { + pFrameNode[pNewTask->frame_idx].access_buf = + &pTxBuf[HSize + i * Addr + 1]; + } + + /* only retry at the first frame */ + pFrameNode[pNewTask->frame_idx].retry_count = 0; + + i++; + } + } else if (Protocol == I3C_TRANSFER_PROTOCOL_CCCr) { + pNewTask->frame_count = (*pWrCnt - HSize) + 1; + pFrameNode = (I3C_TRANSFER_FRAME_t *)hal_I3C_MemAlloc( + sizeof(I3C_TRANSFER_FRAME_t) * pNewTask->frame_count); + + if (pFrameNode == NULL) { + FreeTaskNode(pNewTask); + return I3C_ERR_OUT_OF_MEMORY; + } + + pFrameNode[0].pOwner = pNewTask; + pFrameNode[0].flag = I3C_TRANSFER_NORMAL | I3C_TRANSFER_RETRY_ENABLE | + I3C_TRANSFER_NO_STOP; + pFrameNode[0].type = I3C_TRANSFER_TYPE_SDR; + pFrameNode[0].baudrate = Baudrate; + pFrameNode[0].address = I3C_BROADCAST_ADDR; + pFrameNode[0].direction = I3C_TRANSFER_DIR_WRITE; + pFrameNode[0].access_len = HSize; + pFrameNode[0].access_idx = 0; + pFrameNode[0].access_buf = pTxBuf; /* CCC */ + pFrameNode[0].retry_count = 3; + pFrameNode[0].pNextFrame = &pFrameNode[1]; + + i = 0; + while (1) { + pNewTask->frame_idx = 1 + i; + if (pNewTask->frame_idx == pNewTask->frame_count) { + break; + } + + if (pNewTask->frame_idx == (pNewTask->frame_count - 1)) { + pFrameNode[pNewTask->frame_idx].flag = I3C_TRANSFER_NORMAL | + I3C_TRANSFER_REPEAT_START | + I3C_TRANSFER_RETRY_ENABLE | + I3C_TRANSFER_RETRY_WITHOUT_STOP; + pFrameNode[pNewTask->frame_idx].pNextFrame = NULL; + } else { + pFrameNode[pNewTask->frame_idx].flag = I3C_TRANSFER_NORMAL | + I3C_TRANSFER_REPEAT_START | + I3C_TRANSFER_RETRY_ENABLE | + I3C_TRANSFER_RETRY_WITHOUT_STOP | + I3C_TRANSFER_NO_STOP; + pFrameNode[pNewTask->frame_idx].pNextFrame = + &pFrameNode[pNewTask->frame_idx + 1]; + } + + pFrameNode[pNewTask->frame_idx].pOwner = pNewTask; + pFrameNode[pNewTask->frame_idx].type = I3C_TRANSFER_TYPE_SDR; + pFrameNode[pNewTask->frame_idx].baudrate = Baudrate; + pFrameNode[pNewTask->frame_idx].address = pTxBuf[HSize + i]; + pFrameNode[pNewTask->frame_idx].direction = I3C_TRANSFER_DIR_READ; + + /* Format = Read Data Length per CCC */ + pFrameNode[pNewTask->frame_idx].access_len = Addr; + pFrameNode[pNewTask->frame_idx].access_idx = 0; + pFrameNode[pNewTask->frame_idx].access_buf = &pRxBuf[i * Addr]; + pFrameNode[pNewTask->frame_idx].retry_count = 1; + + i++; + } + } + } else if (EVENT_TRANSFER_PROTOCOL(Protocol)) { + if (Protocol == I3C_TRANSFER_PROTOCOL_EVENT) { + /* For IBI, we should read back MDB + Extended IBI payload. + * For MCTP, we should read back MDB and stop. Then fork a new read transfer + * to read back response data. + * + * For Hot Join, we should accept the request and start ENTDAA after STOP. + * Must STOP to notify slave finish hot-join task. + * Can't use RESTART + ENTDAA, that will cause MERRWARN.INVREQ + * + * For Master Request, we should accept the request and + * start GETACCMST with RESTART + */ + + pNewTask->frame_count = 1; + pFrameNode = (I3C_TRANSFER_FRAME_t *)hal_I3C_MemAlloc( + sizeof(I3C_TRANSFER_FRAME_t) * pNewTask->frame_count); + + if (pFrameNode == NULL) { + FreeTaskNode(pNewTask); + return I3C_ERR_OUT_OF_MEMORY; + } + + pFrameNode[0].pOwner = pNewTask; + /* we don't identify IBI type now, and + * HJ can interrupt IBI and MR, IBI can interrupt MR + * when master doesn't want to ack slave request, + * we need to sent disec with RESTART + */ + pFrameNode[0].flag = I3C_TRANSFER_NORMAL | I3C_TRANSFER_RETRY_ENABLE; + + pFrameNode[0].type = I3C_TRANSFER_TYPE_SDR; + pFrameNode[0].baudrate = Baudrate; + pFrameNode[0].address = I3C_BROADCAST_ADDR; + pFrameNode[0].direction = I3C_TRANSFER_DIR_READ; + pFrameNode[0].access_len = *pRdCnt; + pFrameNode[0].access_idx = 0; + pFrameNode[0].access_buf = pRxBuf; + pFrameNode[0].retry_count = 3; + pFrameNode[0].pNextFrame = NULL; + } else if (Protocol == I3C_TRANSFER_PROTOCOL_IBI) { + pNewTask->frame_count = 1; + pFrameNode = (I3C_TRANSFER_FRAME_t *)hal_I3C_MemAlloc( + sizeof(I3C_TRANSFER_FRAME_t) * pNewTask->frame_count); + + if (pFrameNode == NULL) { + FreeTaskNode(pNewTask); + return I3C_ERR_OUT_OF_MEMORY; + } + + pFrameNode[0].pOwner = pNewTask; + pFrameNode[0].flag = I3C_TRANSFER_NORMAL | I3C_TRANSFER_RETRY_ENABLE; + pFrameNode[0].type = I3C_TRANSFER_TYPE_SDR; + pFrameNode[0].address = I3C_BROADCAST_ADDR; + pFrameNode[0].direction = I3C_TRANSFER_DIR_WRITE; + pFrameNode[0].access_len = (Addr == 0) ? 0 : *pWrCnt; + pFrameNode[0].access_idx = 0; + pFrameNode[0].access_buf = (Addr == 0) ? NULL : pTxBuf; + pFrameNode[0].retry_count = 3; + pFrameNode[0].pNextFrame = NULL; + } else if (Protocol == I3C_TRANSFER_PROTOCOL_MASTER_REQUEST) { + pNewTask->frame_count = 1; + pFrameNode = (I3C_TRANSFER_FRAME_t *)hal_I3C_MemAlloc( + sizeof(I3C_TRANSFER_FRAME_t) * pNewTask->frame_count); + + if (pFrameNode == NULL) { + FreeTaskNode(pNewTask); + return I3C_ERR_OUT_OF_MEMORY; + } + + pFrameNode[0].pOwner = pNewTask; + pFrameNode[0].flag = I3C_TRANSFER_NORMAL | I3C_TRANSFER_RETRY_ENABLE; + pFrameNode[0].type = I3C_TRANSFER_TYPE_SDR; + pFrameNode[0].direction = I3C_TRANSFER_DIR_WRITE; + pFrameNode[0].access_len = 0; + pFrameNode[0].access_idx = 0; + pFrameNode[0].access_buf = NULL; + pFrameNode[0].retry_count = 3; + pFrameNode[0].pNextFrame = NULL; + } else if (Protocol == I3C_TRANSFER_PROTOCOL_HOT_JOIN) { + pNewTask->frame_count = 1; + pFrameNode = (I3C_TRANSFER_FRAME_t *)hal_I3C_MemAlloc( + sizeof(I3C_TRANSFER_FRAME_t) * pNewTask->frame_count); + if (pFrameNode == NULL) { + FreeTaskNode(pNewTask); + return I3C_ERR_OUT_OF_MEMORY; + } + + pFrameNode[0].pOwner = pNewTask; + pFrameNode[0].flag = I3C_TRANSFER_NORMAL | I3C_TRANSFER_RETRY_ENABLE; + pFrameNode[0].type = I3C_TRANSFER_TYPE_SDR; + pFrameNode[0].direction = I3C_TRANSFER_DIR_READ; + pFrameNode[0].access_len = 0; + pFrameNode[0].access_idx = 0; + pFrameNode[0].access_buf = NULL; + pFrameNode[0].retry_count = 3; + pFrameNode[0].pNextFrame = NULL; + } + } else if (WRITE_TRANSFER_PROTOCOL(Protocol)) { + if (I2C_TRANSFER_PROTOCOL(Protocol)) { + pNewTask->frame_count = 1; + pFrameNode = hal_I3C_MemAlloc( + sizeof(I3C_TRANSFER_FRAME_t) * pNewTask->frame_count); + if (pFrameNode == NULL) { + FreeTaskNode(pNewTask); + return I3C_ERR_OUT_OF_MEMORY; + } + + pFrameNode[0].pOwner = pNewTask; + pFrameNode[0].flag = I3C_TRANSFER_NORMAL; + pFrameNode[0].type = I3C_TRANSFER_TYPE_I2C; + pFrameNode[0].baudrate = Baudrate; + pFrameNode[0].address = Addr; + pFrameNode[0].direction = I3C_TRANSFER_DIR_WRITE; + pFrameNode[0].access_len = *pWrCnt; + pFrameNode[0].access_idx = 0; + pFrameNode[0].access_buf = pTxBuf; + pFrameNode[0].retry_count = 0; + pFrameNode[0].pNextFrame = NULL; + } else if (I3C_TRANSFER_PROTOCOL(Protocol)) { + pNewTask->frame_count = 1; + pFrameNode = (I3C_TRANSFER_FRAME_t *)hal_I3C_MemAlloc( + sizeof(I3C_TRANSFER_FRAME_t) * pNewTask->frame_count); + + if (pFrameNode == NULL) { + FreeTaskNode(pNewTask); + return I3C_ERR_OUT_OF_MEMORY; + } + + pFrameNode[0].pOwner = pNewTask; + pFrameNode[0].flag = I3C_TRANSFER_NORMAL | I3C_TRANSFER_RETRY_ENABLE; + pFrameNode[0].type = I3C_TRANSFER_TYPE_SDR; + pFrameNode[0].baudrate = Baudrate; + pFrameNode[0].address = Addr; + pFrameNode[0].direction = I3C_TRANSFER_DIR_WRITE; + pFrameNode[0].access_len = *pWrCnt; + pFrameNode[0].access_idx = 0; + pFrameNode[0].access_buf = pTxBuf; + pFrameNode[0].retry_count = 3; + pFrameNode[0].pNextFrame = NULL; + } else if (DDR_TRANSFER_PROTOCOL(Protocol)) { + pNewTask->frame_count = 1; + pFrameNode = (I3C_TRANSFER_FRAME_t *)hal_I3C_MemAlloc( + sizeof(I3C_TRANSFER_FRAME_t) * pNewTask->frame_count); + + if (pFrameNode == NULL) { + FreeTaskNode(pNewTask); + return I3C_ERR_OUT_OF_MEMORY; + } + + pFrameNode[0].pOwner = pNewTask; + pFrameNode[0].flag = I3C_TRANSFER_NORMAL | I3C_TRANSFER_RETRY_ENABLE; + pFrameNode[0].type = I3C_TRANSFER_TYPE_DDR; + pFrameNode[0].baudrate = Baudrate; + pFrameNode[0].address = Addr; + pFrameNode[0].direction = I3C_TRANSFER_DIR_WRITE; + pFrameNode[0].hdrcmd = pTxBuf[0]; + pFrameNode[0].access_len = *pWrCnt - 1; + pFrameNode[0].access_idx = 0; + pFrameNode[0].access_buf = &pTxBuf[1]; + pFrameNode[0].retry_count = 3; + pFrameNode[0].pNextFrame = NULL; + } + } else if (READ_TRANSFER_PROTOCOL(Protocol)) { + if (I2C_TRANSFER_PROTOCOL(Protocol)) { + pNewTask->frame_count = 1; + pFrameNode = (I3C_TRANSFER_FRAME_t *)hal_I3C_MemAlloc( + sizeof(I3C_TRANSFER_FRAME_t) * pNewTask->frame_count); + + if (pFrameNode == NULL) { + FreeTaskNode(pNewTask); + return I3C_ERR_OUT_OF_MEMORY; + } + + pFrameNode[0].pOwner = pNewTask; + pFrameNode[0].flag = I3C_TRANSFER_NORMAL; + pFrameNode[0].type = I3C_TRANSFER_TYPE_I2C; + pFrameNode[0].baudrate = Baudrate; + pFrameNode[0].address = Addr; + pFrameNode[0].direction = I3C_TRANSFER_DIR_READ; + pFrameNode[0].access_len = *pRdCnt; + pFrameNode[0].access_idx = 0; + pFrameNode[0].access_buf = pRxBuf; + pFrameNode[0].retry_count = 0; + pFrameNode[0].pNextFrame = NULL; + } else if (I3C_TRANSFER_PROTOCOL(Protocol)) { + pNewTask->frame_count = 1; + pFrameNode = (I3C_TRANSFER_FRAME_t *)hal_I3C_MemAlloc( + sizeof(I3C_TRANSFER_FRAME_t) * pNewTask->frame_count); + + if (pFrameNode == NULL) { + FreeTaskNode(pNewTask); + return I3C_ERR_OUT_OF_MEMORY; + } + + pFrameNode[0].pOwner = pNewTask; + pFrameNode[0].flag = I3C_TRANSFER_NORMAL | I3C_TRANSFER_RETRY_ENABLE; + pFrameNode[0].type = I3C_TRANSFER_TYPE_SDR; + pFrameNode[0].baudrate = Baudrate; + pFrameNode[0].address = Addr; + pFrameNode[0].direction = I3C_TRANSFER_DIR_READ; + pFrameNode[0].access_len = *pRdCnt; + pFrameNode[0].access_idx = 0; + pFrameNode[0].access_buf = pRxBuf; + pFrameNode[0].retry_count = 3; + pFrameNode[0].pNextFrame = NULL; + } else if (DDR_TRANSFER_PROTOCOL(Protocol)) { + pNewTask->frame_count = 1; + pFrameNode = (I3C_TRANSFER_FRAME_t *)hal_I3C_MemAlloc(sizeof( + I3C_TRANSFER_FRAME_t) * pNewTask->frame_count); + + if (pFrameNode == NULL) { + FreeTaskNode(pNewTask); + return I3C_ERR_OUT_OF_MEMORY; + } + + pFrameNode[0].pOwner = pNewTask; + pFrameNode[0].flag = I3C_TRANSFER_NORMAL | I3C_TRANSFER_RETRY_ENABLE; + pFrameNode[0].type = I3C_TRANSFER_TYPE_DDR; + pFrameNode[0].baudrate = Baudrate; + pFrameNode[0].address = Addr; + pFrameNode[0].direction = I3C_TRANSFER_DIR_READ; + pFrameNode[0].hdrcmd = pTxBuf[0]; + pFrameNode[0].access_len = *pRdCnt; + pFrameNode[0].access_idx = 0; + pFrameNode[0].access_buf = pRxBuf; + pFrameNode[0].retry_count = 3; + pFrameNode[0].pNextFrame = NULL; + } + } else if (WRITEnREAD_TRANSFER_PROTOCOL(Protocol)) { + if (I2C_TRANSFER_PROTOCOL(Protocol)) { + pNewTask->frame_count = 2; + pFrameNode = (I3C_TRANSFER_FRAME_t *)hal_I3C_MemAlloc( + sizeof(I3C_TRANSFER_FRAME_t) * pNewTask->frame_count); + + if (pFrameNode == NULL) { + FreeTaskNode(pNewTask); + return I3C_ERR_OUT_OF_MEMORY; + } + + pFrameNode[0].pOwner = pNewTask; + pFrameNode[0].flag = I3C_TRANSFER_NORMAL | I3C_TRANSFER_NO_STOP; + pFrameNode[0].type = I3C_TRANSFER_TYPE_I2C; + pFrameNode[0].baudrate = Baudrate; + pFrameNode[0].address = Addr; + pFrameNode[0].direction = I3C_TRANSFER_DIR_WRITE; + pFrameNode[0].access_len = *pWrCnt; + pFrameNode[0].access_idx = 0; + pFrameNode[0].access_buf = pTxBuf; + pFrameNode[0].retry_count = 0; + pFrameNode[0].pNextFrame = &pFrameNode[1]; + + pFrameNode[1].pOwner = pNewTask; + pFrameNode[1].flag = I3C_TRANSFER_NORMAL | I3C_TRANSFER_REPEAT_START | + I3C_TRANSFER_RETRY_ENABLE; + pFrameNode[1].type = I3C_TRANSFER_TYPE_I2C; + pFrameNode[1].baudrate = Baudrate; + pFrameNode[1].address = Addr; + pFrameNode[1].direction = I3C_TRANSFER_DIR_READ; + pFrameNode[1].access_len = *pRdCnt; + pFrameNode[1].access_idx = 0; + pFrameNode[1].access_buf = pRxBuf; + pFrameNode[1].retry_count = 3; + pFrameNode[1].pNextFrame = NULL; + } else if (I3C_TRANSFER_PROTOCOL(Protocol)) { + pNewTask->frame_count = 2; + pFrameNode = (I3C_TRANSFER_FRAME_t *)hal_I3C_MemAlloc( + sizeof(I3C_TRANSFER_FRAME_t) * pNewTask->frame_count); + + if (pFrameNode == NULL) { + FreeTaskNode(pNewTask); + return I3C_ERR_OUT_OF_MEMORY; + } + + pFrameNode[0].pOwner = pNewTask; + pFrameNode[0].flag = I3C_TRANSFER_NORMAL | I3C_TRANSFER_NO_STOP | + I3C_TRANSFER_RETRY_ENABLE; + pFrameNode[0].type = I3C_TRANSFER_TYPE_SDR; + pFrameNode[0].baudrate = Baudrate; + pFrameNode[0].address = Addr; + pFrameNode[0].direction = I3C_TRANSFER_DIR_WRITE; + pFrameNode[0].access_len = *pWrCnt; + pFrameNode[0].access_idx = 0; + pFrameNode[0].access_buf = pTxBuf; + pFrameNode[0].retry_count = 3; + pFrameNode[0].pNextFrame = &pFrameNode[1]; + + pFrameNode[1].pOwner = pNewTask; + pFrameNode[1].flag = I3C_TRANSFER_NORMAL | I3C_TRANSFER_REPEAT_START | + I3C_TRANSFER_RETRY_ENABLE; + pFrameNode[1].type = I3C_TRANSFER_TYPE_SDR; + pFrameNode[1].baudrate = Baudrate; + pFrameNode[1].address = Addr; + pFrameNode[1].direction = I3C_TRANSFER_DIR_READ; + pFrameNode[1].access_len = *pRdCnt; + pFrameNode[1].access_idx = 0; + pFrameNode[1].access_buf = pRxBuf; + pFrameNode[1].retry_count = 3; + pFrameNode[1].pNextFrame = NULL; + } + } else if (W7E_TRANSFER_PROTOCOL(Protocol)) { + if (I2C_TRANSFER_PROTOCOL(Protocol)) { + pNewTask->frame_count = 2; + pFrameNode = (I3C_TRANSFER_FRAME_t *)hal_I3C_MemAlloc( + sizeof(I3C_TRANSFER_FRAME_t) * pNewTask->frame_count); + + if (pFrameNode == NULL) { + FreeTaskNode(pNewTask); + return I3C_ERR_OUT_OF_MEMORY; + } + + pFrameNode[0].pOwner = pNewTask; + pFrameNode[0].flag = I3C_TRANSFER_NORMAL | I3C_TRANSFER_NO_STOP; + pFrameNode[0].type = I3C_TRANSFER_TYPE_I2C; + pFrameNode[0].baudrate = Baudrate; + pFrameNode[0].address = I3C_BROADCAST_ADDR; + pFrameNode[0].direction = I3C_TRANSFER_DIR_WRITE; + pFrameNode[0].access_len = 0; + pFrameNode[0].access_idx = 0; + pFrameNode[0].access_buf = NULL; + pFrameNode[0].retry_count = 0; + pFrameNode[0].pNextFrame = &pFrameNode[1]; + + pFrameNode[1].pOwner = pNewTask; + pFrameNode[1].flag = I3C_TRANSFER_NORMAL | I3C_TRANSFER_REPEAT_START; + pFrameNode[1].type = I3C_TRANSFER_TYPE_I2C; + pFrameNode[1].baudrate = Baudrate; + pFrameNode[1].address = Addr; + pFrameNode[1].direction = I3C_TRANSFER_DIR_WRITE; + pFrameNode[1].access_len = *pWrCnt; + pFrameNode[1].access_idx = 0; + pFrameNode[1].access_buf = pTxBuf; + pFrameNode[1].retry_count = 0; + pFrameNode[1].pNextFrame = NULL; + } else if (I3C_TRANSFER_PROTOCOL(Protocol)) { + pNewTask->frame_count = 2; + pFrameNode = (I3C_TRANSFER_FRAME_t *)hal_I3C_MemAlloc( + sizeof(I3C_TRANSFER_FRAME_t) * pNewTask->frame_count); + + if (pFrameNode == NULL) { + FreeTaskNode(pNewTask); + return I3C_ERR_OUT_OF_MEMORY; + } + + pFrameNode[0].pOwner = pNewTask; + pFrameNode[0].flag = I3C_TRANSFER_NORMAL | I3C_TRANSFER_NO_STOP | + I3C_TRANSFER_RETRY_ENABLE; + pFrameNode[0].type = I3C_TRANSFER_TYPE_SDR; + pFrameNode[0].baudrate = Baudrate; + pFrameNode[0].address = I3C_BROADCAST_ADDR; + pFrameNode[0].direction = I3C_TRANSFER_DIR_WRITE; + pFrameNode[0].access_len = 0; + pFrameNode[0].access_idx = 0; + pFrameNode[0].access_buf = NULL; + pFrameNode[0].retry_count = 3; + pFrameNode[0].pNextFrame = &pFrameNode[1]; + + pFrameNode[1].pOwner = pNewTask; + pFrameNode[1].flag = I3C_TRANSFER_NORMAL | I3C_TRANSFER_REPEAT_START; + pFrameNode[1].type = I3C_TRANSFER_TYPE_SDR; + pFrameNode[1].baudrate = Baudrate; + pFrameNode[1].address = Addr; + pFrameNode[1].direction = I3C_TRANSFER_DIR_WRITE; + pFrameNode[1].access_len = *pWrCnt; + pFrameNode[1].access_idx = 0; + pFrameNode[1].access_buf = pTxBuf; + pFrameNode[1].retry_count = 0; + pFrameNode[1].pNextFrame = NULL; + } + } else if (R7E_TRANSFER_PROTOCOL(Protocol)) { + if (I2C_TRANSFER_PROTOCOL(Protocol)) { + pNewTask->frame_count = 2; + pFrameNode = (I3C_TRANSFER_FRAME_t *)hal_I3C_MemAlloc( + sizeof(I3C_TRANSFER_FRAME_t) * pNewTask->frame_count); + if (pFrameNode == NULL) { + FreeTaskNode(pNewTask); + return I3C_ERR_OUT_OF_MEMORY; + } + + pFrameNode[0].pOwner = pNewTask; + pFrameNode[0].flag = I3C_TRANSFER_NORMAL | I3C_TRANSFER_NO_STOP; + pFrameNode[0].type = I3C_TRANSFER_TYPE_I2C; + pFrameNode[0].baudrate = Baudrate; + pFrameNode[0].address = I3C_BROADCAST_ADDR; + pFrameNode[0].direction = I3C_TRANSFER_DIR_WRITE; + pFrameNode[0].access_len = 0; + pFrameNode[0].access_idx = 0; + pFrameNode[0].access_buf = NULL; + pFrameNode[0].retry_count = 0; + pFrameNode[0].pNextFrame = &pFrameNode[1]; + + pFrameNode[1].pOwner = pNewTask; + pFrameNode[1].flag = I3C_TRANSFER_NORMAL | I3C_TRANSFER_REPEAT_START; + pFrameNode[1].type = I3C_TRANSFER_TYPE_I2C; + pFrameNode[1].baudrate = Baudrate; + pFrameNode[1].address = Addr; + pFrameNode[1].direction = I3C_TRANSFER_DIR_READ; + pFrameNode[1].access_len = *pRdCnt; + pFrameNode[1].access_idx = 0; + pFrameNode[1].access_buf = pRxBuf; + pFrameNode[1].retry_count = 0; + pFrameNode[1].pNextFrame = NULL; + } else if (I3C_TRANSFER_PROTOCOL(Protocol)) { + pNewTask->frame_count = 2; + pFrameNode = (I3C_TRANSFER_FRAME_t *)hal_I3C_MemAlloc( + sizeof(I3C_TRANSFER_FRAME_t) * pNewTask->frame_count); + + if (pFrameNode == NULL) { + FreeTaskNode(pNewTask); + return I3C_ERR_OUT_OF_MEMORY; + } + + pFrameNode[0].pOwner = pNewTask; + pFrameNode[0].flag = I3C_TRANSFER_NORMAL | I3C_TRANSFER_NO_STOP | + I3C_TRANSFER_RETRY_ENABLE; + pFrameNode[0].type = I3C_TRANSFER_TYPE_SDR; + pFrameNode[0].baudrate = Baudrate; + pFrameNode[0].address = I3C_BROADCAST_ADDR; + pFrameNode[0].direction = I3C_TRANSFER_DIR_WRITE; + pFrameNode[0].access_len = 0; + pFrameNode[0].access_idx = 0; + pFrameNode[0].access_buf = NULL; + pFrameNode[0].retry_count = 3; + pFrameNode[0].pNextFrame = &pFrameNode[1]; + + pFrameNode[1].pOwner = pNewTask; + pFrameNode[1].flag = I3C_TRANSFER_NORMAL | I3C_TRANSFER_REPEAT_START | + I3C_TRANSFER_RETRY_ENABLE; + pFrameNode[1].type = I3C_TRANSFER_TYPE_SDR; + pFrameNode[1].baudrate = Baudrate; + pFrameNode[1].address = Addr; + pFrameNode[1].direction = I3C_TRANSFER_DIR_READ; + pFrameNode[1].access_len = *pRdCnt; + pFrameNode[1].access_idx = 0; + pFrameNode[1].access_buf = pRxBuf; + pFrameNode[1].retry_count = 3; + pFrameNode[1].pNextFrame = NULL; + } + } else if (W7EnREAD_TRANSFER_PROTOCOL(Protocol)) { + if (I2C_TRANSFER_PROTOCOL(Protocol)) { + pNewTask->frame_count = 3; + pFrameNode = (I3C_TRANSFER_FRAME_t *)hal_I3C_MemAlloc( + sizeof(I3C_TRANSFER_FRAME_t) * pNewTask->frame_count); + + if (pFrameNode == NULL) { + FreeTaskNode(pNewTask); + return I3C_ERR_OUT_OF_MEMORY; + } + + pFrameNode[0].pOwner = pNewTask; + pFrameNode[0].flag = I3C_TRANSFER_NORMAL | I3C_TRANSFER_NO_STOP; + pFrameNode[0].type = I3C_TRANSFER_TYPE_I2C; + pFrameNode[0].baudrate = Baudrate; + pFrameNode[0].address = I3C_BROADCAST_ADDR; + pFrameNode[0].direction = I3C_TRANSFER_DIR_WRITE; + pFrameNode[0].access_len = 0; + pFrameNode[0].access_idx = 0; + pFrameNode[0].access_buf = NULL; + pFrameNode[0].retry_count = 0; + pFrameNode[0].pNextFrame = &pFrameNode[1]; + + pFrameNode[1].pOwner = pNewTask; + pFrameNode[1].flag = I3C_TRANSFER_NORMAL | I3C_TRANSFER_REPEAT_START | + I3C_TRANSFER_NO_STOP; + pFrameNode[1].type = I3C_TRANSFER_TYPE_I2C; + pFrameNode[1].baudrate = Baudrate; + pFrameNode[1].address = Addr; + pFrameNode[1].direction = I3C_TRANSFER_DIR_WRITE; + pFrameNode[1].access_len = *pWrCnt; + pFrameNode[1].access_idx = 0; + pFrameNode[1].access_buf = pTxBuf; + pFrameNode[1].retry_count = 0; + pFrameNode[1].pNextFrame = &pFrameNode[2]; + + pFrameNode[2].pOwner = pNewTask; + pFrameNode[2].flag = I3C_TRANSFER_NORMAL | I3C_TRANSFER_REPEAT_START; + pFrameNode[2].type = I3C_TRANSFER_TYPE_I2C; + pFrameNode[2].baudrate = Baudrate; + pFrameNode[2].address = Addr; + pFrameNode[2].direction = I3C_TRANSFER_DIR_READ; + pFrameNode[2].access_len = *pRdCnt; + pFrameNode[2].access_idx = 0; + pFrameNode[2].access_buf = pRxBuf; + pFrameNode[2].retry_count = 0; + pFrameNode[2].pNextFrame = NULL; + } else if (I3C_TRANSFER_PROTOCOL(Protocol)) { + pNewTask->frame_count = 3; + pFrameNode = (I3C_TRANSFER_FRAME_t *)hal_I3C_MemAlloc( + sizeof(I3C_TRANSFER_FRAME_t) * pNewTask->frame_count); + + if (pFrameNode == NULL) { + FreeTaskNode(pNewTask); + return I3C_ERR_OUT_OF_MEMORY; + } + + pFrameNode[0].pOwner = pNewTask; + pFrameNode[0].flag = I3C_TRANSFER_NORMAL | I3C_TRANSFER_NO_STOP | + I3C_TRANSFER_RETRY_ENABLE; + pFrameNode[0].type = I3C_TRANSFER_TYPE_SDR; + pFrameNode[0].baudrate = Baudrate; + pFrameNode[0].address = I3C_BROADCAST_ADDR; + pFrameNode[0].direction = I3C_TRANSFER_DIR_WRITE; + pFrameNode[0].access_len = 0; + pFrameNode[0].access_idx = 0; + pFrameNode[0].access_buf = NULL; + pFrameNode[0].retry_count = 3; + pFrameNode[0].pNextFrame = &pFrameNode[1]; + + pFrameNode[1].pOwner = pNewTask; + pFrameNode[1].flag = I3C_TRANSFER_NORMAL | I3C_TRANSFER_REPEAT_START | + I3C_TRANSFER_NO_STOP | I3C_TRANSFER_RETRY_ENABLE; + pFrameNode[1].type = I3C_TRANSFER_TYPE_SDR; + pFrameNode[1].baudrate = Baudrate; + pFrameNode[1].address = Addr; + pFrameNode[1].direction = I3C_TRANSFER_DIR_WRITE; + pFrameNode[1].access_len = *pWrCnt; + pFrameNode[1].access_idx = 0; + pFrameNode[1].access_buf = pTxBuf; + pFrameNode[1].retry_count = 3; + pFrameNode[1].pNextFrame = &pFrameNode[2]; + + pFrameNode[2].pOwner = pNewTask; + pFrameNode[2].flag = I3C_TRANSFER_NORMAL | I3C_TRANSFER_REPEAT_START | + I3C_TRANSFER_RETRY_ENABLE; + pFrameNode[2].type = I3C_TRANSFER_TYPE_SDR; + pFrameNode[2].baudrate = Baudrate; + pFrameNode[2].address = Addr; + pFrameNode[2].direction = I3C_TRANSFER_DIR_READ; + pFrameNode[2].access_len = *pRdCnt; + pFrameNode[2].access_idx = 0; + pFrameNode[2].access_buf = pRxBuf; + pFrameNode[2].retry_count = 3; + pFrameNode[2].pNextFrame = NULL; + } + } + + if (pFrameNode == NULL) { + FreeTaskNode(pNewTask); + return I3C_ERR_PARAMETER_INVALID; + } + + pNewTask->frame_idx = 0; + pNewTask->pFrameList = pFrameNode; + pNewTask->pTaskInfo = pTaskInfo; + pNewTask->protocol = Protocol; + pNewTask->address = Addr; + pNewTask->baudrate = Baudrate; + pNewTask->pNextTask = NULL; + pTaskInfo->bHIF = bHIF; + pTaskInfo->pTask = pNewTask; + pTaskInfo->callback = callback; + + return I3C_ERR_OK; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Insert task into device's task list + * @param [in] pDevice Specify device + * @param [in] pNewTask Task to be inserted + * @param [in] bType insert policy, 0: first, 1: last + * @return I3C_ERR_OK, if the task insert successfully + */ +/*------------------------------------------------------------------------------*/ +I3C_ErrCode_Enum InsertTaskNode(I3C_DEVICE_INFO_t *pDevice, + I3C_TRANSFER_TASK_t *pNewTask, __u8 bType) +{ + I3C_TRANSFER_TASK_t *pNextTask; + I3C_TRANSFER_TASK_t *pThisTask; + + if (pDevice == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + + if (pNewTask == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + + pThisTask = pDevice->pTaskListHead; + if (pThisTask == NULL) { + pDevice->pTaskListHead = pNewTask; + return I3C_ERR_OK; + } + + if (bType == 0) { + pNewTask->pNextTask = pThisTask; + pDevice->pTaskListHead = pNewTask; + return I3C_ERR_OK; + } + + if (bType == 1) { + while (pThisTask->pNextTask != NULL) { + pThisTask = pThisTask->pNextTask; + } + + pThisTask->pNextTask = pNewTask; + return I3C_ERR_OK; + } + + if (pThisTask->protocol != I3C_TRANSFER_PROTOCOL_EVENT) { + pNewTask->pNextTask = pThisTask; + pDevice->pTaskListHead = pNewTask; + return I3C_ERR_OK; + } + +CHECK_NEXT: + pNextTask = pThisTask->pNextTask; + if (pNextTask == NULL) { + pThisTask->pNextTask = pNewTask; + return I3C_ERR_OK; + } + + if (pNextTask->protocol != I3C_TRANSFER_PROTOCOL_EVENT) { + pNewTask->pNextTask = pThisTask->pNextTask; + pThisTask->pNextTask = pNewTask; + return I3C_ERR_OK; + } + + pThisTask = pNextTask; + goto CHECK_NEXT; + + return I3C_ERR_OK; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Create ENTDAA task into device's task list + * @param [in] rxbuf_size receive buffer length + * @param [in] rxbuf receive buffer to store participated slave device info + * @param [in] Baudrate baudrate to generate ENTDAA + * @param [in] Timeout task timeout value + * @param [in] callback callback + * @param [in] PortId + * @param [in] Policy task insertion policy + * @param [in] bHIF bHIF = 1, the receive buffer will be free automatically + * if task is finished + * @return I3C_ERR_OK, if the task insert successfully + */ +/*------------------------------------------------------------------------------*/ +I3C_ErrCode_Enum I3C_Master_Insert_Task_ENTDAA(__u16 rxbuf_size, __u8 *rxbuf, + __u32 Baudrate, __u32 Timeout, ptrI3C_RetFunc callback, __u8 PortId, + I3C_TASK_POLICY_Enum Policy, _Bool bHIF) +{ + I3C_TASK_INFO_t *pNewTaskInfo; + __u8 TxBuf[1]; + __u16 TxLen; + __u16 RxLen; + I3C_ErrCode_Enum result; + + if (rxbuf_size < 9) { + return I3C_ERR_PARAMETER_INVALID; + } + + if ((bHIF == IS_HIF) && (rxbuf == NULL)) { + return I3C_ERR_PARAMETER_INVALID; + } + + TxBuf[0] = CCC_BROADCAST_ENTDAA; + TxLen = 1; + RxLen = (rxbuf_size / 9) * 9; + pNewTaskInfo = I3C_Master_Create_Task(I3C_TRANSFER_PROTOCOL_ENTDAA, 0, TxLen, + &TxLen, &RxLen, TxBuf, rxbuf, Baudrate, Timeout, I3C_Master_Callback, PortId, + Policy, bHIF); + + if (pNewTaskInfo == NULL) { + return I3C_ERR_OUT_OF_MEMORY; + } + + if ((pNewTaskInfo->result != I3C_ERR_PENDING) && (pNewTaskInfo->result != I3C_ERR_OK)) { + result = pNewTaskInfo->result; + hal_I3C_MemFree(pNewTaskInfo); + return result; + } + + return I3C_ERR_OK; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Create CCCb type task into device's task list + * @param[in] CCC CCC + * @param[in] buf_size write data length, not including CCC + * @param[in] buf write data buffer, not including CCC + * @param [in] Baudrate baudrate to generate CCCb task + * @param [in] Timeout task timeout value + * @param [in] callback callback + * @param [in] PortId + * @param [in] Policy task insertion policy + * @param [in] bHIF bHIF = 1, the receive buffer will be free automatically + * if task is finished + * @return I3C_ERR_OK, if the task insert successfully + */ +/*------------------------------------------------------------------------------*/ +I3C_ErrCode_Enum I3C_Master_Insert_Task_CCCb(__u8 CCC, __u16 buf_size, __u8 *buf, + __u32 Baudrate, __u32 Timeout, ptrI3C_RetFunc callback, __u8 PortId, + I3C_TASK_POLICY_Enum Policy, _Bool bHIF) +{ + I3C_TASK_INFO_t *pNewTaskInfo; + __u8 TxBuf[I3C_PAYLOAD_SIZE_MAX]; + __u16 TxLen; + __u16 RxLen; + I3C_ErrCode_Enum result; + __u16 i; + + if ((buf_size > 0) && (buf == NULL)) { + return I3C_ERR_PARAMETER_INVALID; + } + + if (buf_size > 68) { + return I3C_ERR_PARAMETER_INVALID; + } + + TxBuf[0] = CCC; + TxLen = 1; + RxLen = 0; + + if (buf_size != 0) { + for (i = 0; i < buf_size; i++) { + TxBuf[i + 1] = buf[i]; + } + + TxLen = TxLen + buf_size; + } + + pNewTaskInfo = I3C_Master_Create_Task(I3C_TRANSFER_PROTOCOL_CCCb, 0, + TxLen, &TxLen, &RxLen, TxBuf, NULL, Baudrate, Timeout, callback, PortId, + Policy, bHIF); + + if (pNewTaskInfo == NULL) { + return I3C_ERR_OUT_OF_MEMORY; + } + + if ((pNewTaskInfo->result != I3C_ERR_PENDING) && + (pNewTaskInfo->result != I3C_ERR_OK)) { + result = pNewTaskInfo->result; + hal_I3C_MemFree(pNewTaskInfo); + return result; + } + + return I3C_ERR_OK; +} + +/*------------------------------------------------------------------------------*/ +/** + * + * @brief Create CCCw type task into device's task list + * @param[in] CCC CCC + * @param[in] HSize write data length in the first frame including CCC + * @param[in] buf_size write data length, not including CCC + * @param[in] buf write data buffer, not including CCC + * @param [in] Baudrate baudrate to generate CCCw task + * @param [in] Timeout task timeout value + * @param [in] callback callback + * @param [in] PortId + * @param [in] Policy task insertion policy + * @param [in] bHIF bHIF = 1, the receive buffer will be free automatically + * if task is finished + * @return I3C_ERR_OK, if the task insert successfully + */ +/*------------------------------------------------------------------------------*/ +I3C_ErrCode_Enum I3C_Master_Insert_Task_CCCw(__u8 CCC, __u8 HSize, __u16 buf_size, + __u8 *buf, __u32 Baudrate, __u32 Timeout, ptrI3C_RetFunc callback, __u8 PortId, + I3C_TASK_POLICY_Enum Policy, _Bool bHIF) +{ + I3C_TASK_INFO_t *pNewTaskInfo; + __u8 TxBuf[70]; + __u16 TxLen; + __u16 RxLen; + I3C_ErrCode_Enum result; + __u16 i; + __u8 fmt; + __u16 dev_count; + + if (HSize < 1) { + return I3C_ERR_PARAMETER_INVALID; + } + + if (buf_size == 0) { + return I3C_ERR_PARAMETER_INVALID; + } + + if (buf == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + + if ((HSize - 1) > buf_size) { + return I3C_ERR_PARAMETER_INVALID; + } + + if (buf_size > 63) { + return I3C_ERR_PARAMETER_INVALID; + } + + TxBuf[0] = CCC; + TxLen = 1; + RxLen = 0; + + if (buf_size) { + for (i = 0; i < buf_size; i++) { + TxBuf[i + 1] = buf[i]; + } + + TxLen = 1 + buf_size; + } + + if ((CCC == CCC_DIRECT_ENTAS0) || (CCC == CCC_DIRECT_ENTAS1) || + (CCC == CCC_DIRECT_ENTAS2) || (CCC == CCC_DIRECT_ENTAS3) || + (CCC == CCC_DIRECT_RSTDAA) || (CCC == CCC_DIRECT_RSTACT) || + (CCC == CCC_DIRECT_RSTGRPA)) { + if ((CCC == CCC_DIRECT_RSTACT) && (HSize <= 1)) { + return I3C_ERR_PARAMETER_INVALID; + } + + fmt = 1; + } else if ((CCC == CCC_DIRECT_ENEC) || (CCC == CCC_DIRECT_DISEC) || + (CCC == CCC_DIRECT_SETDASA) || (CCC == CCC_DIRECT_SETNEWDA) || + (CCC == CCC_DIRECT_ENDXFER) || (CCC == CCC_DIRECT_SETGRPA) || + (CCC == CCC_DIRECT_MLANE)) { + if ((CCC == CCC_DIRECT_ENDXFER) && (HSize <= 1)) { + return I3C_ERR_PARAMETER_INVALID; + } + + fmt = 2; + } else if (CCC == CCC_DIRECT_SETMWL) { + fmt = 3; + } else if (CCC == CCC_DIRECT_SETMRL) { + fmt = 4; + } else if ((CCC == CCC_DIRECT_SETBRGTGT) || (CCC == CCC_DIRECT_SETROUTE) || + (CCC == CCC_DIRECT_SETXTIME)) { + fmt = buf_size - (HSize - 1); + } else if (CCC == CCC_DIRECT_MLANE) { + return I3C_ERR_HW_NOT_SUPPORT; + } else { + return I3C_ERR_HW_NOT_SUPPORT; + } + + dev_count = buf_size - (HSize - 1) / fmt; + if (dev_count < 1) { + return I3C_ERR_PARAMETER_INVALID; + } + + pNewTaskInfo = I3C_Master_Create_Task(I3C_TRANSFER_PROTOCOL_CCCw, fmt, HSize, + &TxLen, &RxLen, TxBuf, NULL, Baudrate, Timeout, callback, PortId, Policy, bHIF); + if (pNewTaskInfo == NULL) { + return I3C_ERR_OUT_OF_MEMORY; + } + + if ((pNewTaskInfo->result != I3C_ERR_PENDING) && (pNewTaskInfo->result != I3C_ERR_OK)) { + result = pNewTaskInfo->result; + hal_I3C_MemFree(pNewTaskInfo); + return result; + } + + return I3C_ERR_OK; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Create CCCr type task into device's task list + * @param[in] CCC CCC + * @param[in] HSize write data length in the first frame including CCC + * @param[in] txbuf_size write data length, not including CCC + * @param[in] rxbuf_size read data length + * @param[in] txbuf write data buffer, not including CCC + * @param[in] rxbuf read data buffer + * @param [in] Baudrate baudrate to generate CCCr task + * @param [in] Timeout task timeout value + * @param [in] callback callback + * @param [in] PortId + * @param [in] Policy task insertion policy + * @param [in] bHIF bHIF = 1, the receive buffer will be free automatically + * if task is finished + * @return I3C_ERR_OK, if the task insert successfully + */ +/*------------------------------------------------------------------------------*/ +I3C_ErrCode_Enum I3C_Master_Insert_Task_CCCr(__u8 CCC, __u8 HSize, __u16 txbuf_size, + __u16 rxbuf_size, __u8 *txbuf, __u8 *rxbuf, __u32 Baudrate, __u32 Timeout, + ptrI3C_RetFunc callback, __u8 PortId, I3C_TASK_POLICY_Enum Policy, _Bool bHIF) +{ + I3C_TASK_INFO_t *pNewTaskInfo; + __u8 TxBuf[70]; + __u16 TxLen; + __u16 RxLen; + I3C_ErrCode_Enum result; + __u16 i; + __u8 fmt = 0; + __u16 dev_count; + + if (HSize < 1) { + return I3C_ERR_PARAMETER_INVALID; + } + + if ((HSize - 1) > txbuf_size) { + return I3C_ERR_PARAMETER_INVALID; + } + + if (txbuf_size == 0) { + return I3C_ERR_PARAMETER_INVALID; + } + + if (txbuf_size > 63) { + return I3C_ERR_PARAMETER_INVALID; + } + + if (rxbuf_size == 0) { + return I3C_ERR_PARAMETER_INVALID; + } + + if (rxbuf_size > 64) { + return I3C_ERR_PARAMETER_INVALID; + } + + dev_count = txbuf_size - (HSize - 1); + if (dev_count > rxbuf_size) { + return I3C_ERR_PARAMETER_INVALID; + } + + TxBuf[0] = CCC; + TxLen = 1; + + if (txbuf_size) { + for (i = 0; i < txbuf_size; i++) { + TxBuf[i + 1] = txbuf[i]; + } + + TxLen = 1 + txbuf_size; + } + + if ((CCC == CCC_DIRECT_GETBCR) || (CCC == CCC_DIRECT_GETDCR) || + (CCC == CCC_DIRECT_GETACCCR)) { + fmt = 1; + } else if (CCC == CCC_DIRECT_GETMWL) { + fmt = 2; + } else if (CCC == CCC_DIRECT_GETMRL) { + fmt = 3; + } else if (CCC == CCC_DIRECT_GETXTIME) { + fmt = 4; + } else if (CCC == CCC_DIRECT_GETPID) { + fmt = 6; + } else if (CCC == CCC_DIRECT_GETSTATUS) { + if (HSize == 1) { + fmt = 2; + } else if (TxBuf[1] == 0x00) { + fmt = 2; + } else if (TxBuf[1] == 0x91) { + fmt = 2; + } else { + fmt = rxbuf_size / dev_count; + } + } else if (CCC == CCC_DIRECT_GETMXDS) { + if (HSize == 1) { + fmt = 5; + } else if (TxBuf[1] == 0x91) { + fmt = 1; + } else { + fmt = rxbuf_size / dev_count; + } + } else if (CCC == CCC_DIRECT_GETCAPS) { + if (HSize == 1) { + fmt = 4; + } else { + fmt = rxbuf_size / dev_count; + } + } + + if ((dev_count * fmt) < rxbuf_size) { + return I3C_ERR_PARAMETER_INVALID; + } + RxLen = rxbuf_size; + + pNewTaskInfo = I3C_Master_Create_Task(I3C_TRANSFER_PROTOCOL_CCCr, fmt, HSize, + &TxLen, &RxLen, TxBuf, rxbuf, Baudrate, Timeout, callback, PortId, Policy, bHIF); + + if (pNewTaskInfo == NULL) { + return I3C_ERR_OUT_OF_MEMORY; + } + + if ((pNewTaskInfo->result != I3C_ERR_PENDING) && + (pNewTaskInfo->result != I3C_ERR_OK)) { + result = pNewTaskInfo->result; + hal_I3C_MemFree(pNewTaskInfo); + return result; + } + + return I3C_ERR_OK; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Create Event task into device's task list + * @param[in] rxbuf_size read data length + * @param[in] rxbuf read data buffer + * @param [in] Baudrate baudrate to generate Event task + * @param [in] Timeout task timeout value + * @param [in] callback callback + * @param [in] PortId + * @param [in] Policy task insertion policy + * @param [in] bHIF bHIF = 1, the receive buffer will be free automatically + * if task is finished + * @return I3C_ERR_OK, if the task insert successfully + */ +/*------------------------------------------------------------------------------*/ +I3C_ErrCode_Enum I3C_Master_Insert_Task_EVENT(__u16 rxbuf_size, __u8 *rxbuf, __u32 Baudrate, + __u32 Timeout, ptrI3C_RetFunc callback, __u8 PortId, I3C_TASK_POLICY_Enum Policy, + _Bool bHIF) +{ + I3C_TASK_INFO_t *pNewTaskInfo; + __u16 TxLen; + __u16 RxLen; + I3C_ErrCode_Enum result; + + if ((bHIF == IS_HIF) && (rxbuf == NULL)) { + return I3C_ERR_PARAMETER_INVALID; + } + + TxLen = 0; + + /* ibi payload should not more than 255 byte specified in GETMRL if supported */ + RxLen = rxbuf_size; + pNewTaskInfo = I3C_Master_Create_Task(I3C_TRANSFER_PROTOCOL_EVENT, I3C_BROADCAST_ADDR, 0, + &TxLen, &RxLen, NULL, rxbuf, Baudrate, Timeout, callback, PortId, Policy, bHIF); + + if (pNewTaskInfo == NULL) { + return I3C_ERR_OUT_OF_MEMORY; + } + + if ((pNewTaskInfo->result != I3C_ERR_PENDING) && (pNewTaskInfo->result != I3C_ERR_OK)) { + result = pNewTaskInfo->result; + hal_I3C_MemFree(pNewTaskInfo); + return result; + } + + return I3C_ERR_OK; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Create Hot-Join task into device's task list + * @param [in] port + * @return I3C_ERR_OK, if the task insert successfully + */ +/*------------------------------------------------------------------------------*/ +I3C_ErrCode_Enum I3C_Slave_Insert_Task_HotJoin(I3C_PORT_Enum port) +{ + I3C_TASK_INFO_t *pNewTaskInfo; + I3C_ErrCode_Enum result; + __u16 TxLen, RxLen; + + TxLen = 0; + RxLen = 0; + pNewTaskInfo = I3C_Slave_Create_Task(I3C_TRANSFER_PROTOCOL_HOT_JOIN, 0, &TxLen, &RxLen, + NULL, NULL, TIMEOUT_TYPICAL, I3C_Slave_Callback, port, NOT_HIF); + + if (pNewTaskInfo == NULL) { + return I3C_ERR_OUT_OF_MEMORY; + } + + if ((pNewTaskInfo->result != I3C_ERR_PENDING) && (pNewTaskInfo->result != I3C_ERR_OK)) { + result = pNewTaskInfo->result; + hal_I3C_MemFree(pNewTaskInfo); + return result; + } + + return I3C_ERR_OK; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Create Master-Request task into device's task list + * @param [in] port + * @return I3C_ERR_OK, if the task insert successfully + */ +/*------------------------------------------------------------------------------*/ +I3C_ErrCode_Enum I3C_Slave_Insert_Task_MasterRequest(I3C_PORT_Enum port) +{ + I3C_TASK_INFO_t *pNewTaskInfo; + I3C_ErrCode_Enum result; + __u16 TxLen, RxLen; + + TxLen = 0; + RxLen = 0; + pNewTaskInfo = I3C_Slave_Create_Task(I3C_TRANSFER_PROTOCOL_MASTER_REQUEST, 0, + &TxLen, &RxLen, NULL, NULL, TIMEOUT_TYPICAL, I3C_Slave_Callback, port, NOT_HIF); + if (pNewTaskInfo == NULL) { + return I3C_ERR_OUT_OF_MEMORY; + } + + if ((pNewTaskInfo->result != I3C_ERR_PENDING) && + (pNewTaskInfo->result != I3C_ERR_OK)) { + result = pNewTaskInfo->result; + hal_I3C_MemFree(pNewTaskInfo); + return result; + } + + return I3C_ERR_OK; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Create IBI task into device's task list + * @param [in] port + * @param [in] txbuf_size write data length + * @param [in] txbuf write data buffer + * @return I3C_ERR_OK, if the task insert successfully + */ +/*------------------------------------------------------------------------------*/ +I3C_ErrCode_Enum I3C_Slave_Insert_Task_IBI(I3C_PORT_Enum port, __u16 txbuf_size, __u8 *txbuf) +{ + I3C_TASK_INFO_t *pNewTaskInfo; + I3C_ErrCode_Enum result; + __u16 TxLen, RxLen; + + if (hal_I3C_run_ASYN0(port)) { + TxLen = txbuf_size + 3; + } else { + TxLen = txbuf_size; + } + + RxLen = 0; + + pNewTaskInfo = I3C_Slave_Create_Task(I3C_TRANSFER_PROTOCOL_IBI, 1, + &TxLen, &RxLen, txbuf, NULL, TIMEOUT_TYPICAL, NULL, port, NOT_HIF); + + if (pNewTaskInfo == NULL) { + return I3C_ERR_OUT_OF_MEMORY; + } + + if ((pNewTaskInfo->result != I3C_ERR_PENDING) && + (pNewTaskInfo->result != I3C_ERR_OK)) { + result = pNewTaskInfo->result; + hal_I3C_MemFree(pNewTaskInfo); + return result; + } + + return I3C_ERR_OK; +} + +void BUS_RESET_PORT1(void) +{ +} + +void BUS_RESET_PORT2(void) +{ +} + +void BUS_CLEAR_PORT1(void) +{ +} + +void BUS_CLEAR_PORT2(void) +{ +} diff --git a/drivers/i3c/NPCM4XX/i3c_master.c b/drivers/i3c/NPCM4XX/i3c_master.c new file mode 100644 index 00000000000000..51903c1b1b3d1f --- /dev/null +++ b/drivers/i3c/NPCM4XX/i3c_master.c @@ -0,0 +1,1540 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(npcm4xx_i3c_master, CONFIG_I3C_LOG_LEVEL); + +/** + * @brief Callback for I3C master + * @param [in] TaskInfo Pointer to the running task + * @param [in] ErrDetail task result + * @return final task result + */ + +__u32 I3C_Master_Callback(__u32 TaskInfo, __u32 ErrDetail) +{ + const struct device *dev; + struct i3c_npcm4xx_obj *obj; + struct i3c_npcm4xx_xfer *xfer; + I3C_TASK_INFO_t *pTaskInfo; + I3C_TRANSFER_TASK_t *pTask; + I3C_DEVICE_INFO_t *pDevice; + I3C_BUS_INFO_t *pBus; + __u32 ret; + + if (TaskInfo == 0) { + return I3C_ERR_PARAMETER_INVALID; + } + + pTaskInfo = (I3C_TASK_INFO_t *) TaskInfo; + + if (pTaskInfo->Port == I3C1_IF) { +#if DT_NODE_HAS_STATUS(DT_NODELABEL(i3c0), okay) + dev = DEVICE_DT_GET(DT_NODELABEL(i3c0)); + __ASSERT_NO_MSG(device_is_ready(dev)); +#endif + } else if (pTaskInfo->Port == I3C2_IF) { +#if DT_NODE_HAS_STATUS(DT_NODELABEL(i3c1), okay) + dev = DEVICE_DT_GET(DT_NODELABEL(i3c1)); + __ASSERT_NO_MSG(device_is_ready(dev)); +#endif + } else { + + } + + obj = DEV_DATA(dev); + xfer = obj->curr_xfer; + + if (ErrDetail == I3C_ERR_NACK) { + return I3C_DO_NACK(pTaskInfo); + } + + /* if (ErrDetail == I3C_ERR_WRABT) { return I3C_DO_WRABT(pTaskInfo); } */ + if (ErrDetail == I3C_ERR_SLVSTART) { + return I3C_DO_SLVSTART(pTaskInfo); + } + if (ErrDetail == I3C_ERR_SW_TIMEOUT) { + return I3C_DO_SW_TIMEOUT(pTaskInfo); + } + + if (ErrDetail == I3C_ERR_IBI) { + return I3C_DO_IBI(pTaskInfo); + } + if (ErrDetail == I3C_ERR_HJ) { + return I3C_DO_HOT_JOIN(pTaskInfo); + } + if (ErrDetail == I3C_ERR_MR) { + return I3C_DO_MASTER_REQUEST(pTaskInfo); + } + + if (pTaskInfo->pTask == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + if (pTaskInfo->Port >= I3C_PORT_MAX) { + return I3C_ERR_PARAMETER_INVALID; + } + + pTask = pTaskInfo->pTask; + pDevice = I3C_Get_INODE(pTaskInfo->Port); + pBus = pDevice->pOwner; + + if (pTask->protocol == I3C_TRANSFER_PROTOCOL_ENTDAA) { + I3C_DO_ENTDAA(pTaskInfo); + } + + if (CCC_TRANSFER_PROTOCOL(pTask->protocol)) { + if (pTask->pWrBuf[0] == CCC_BROADCAST_ENEC) { + I3C_DO_ENEC(pTaskInfo); + } + if (pTask->pWrBuf[0] == CCC_BROADCAST_DISEC) { + I3C_DO_DISEC(pTaskInfo); + } + /* + * if (pTask->pWrBuf[0] == CCC_BROADCAST_ENTAS0) + * if (pTask->pWrBuf[0] == CCC_BROADCAST_ENTAS1) + * if (pTask->pWrBuf[0] == CCC_BROADCAST_ENTAS2) + * if (pTask->pWrBuf[0] == CCC_BROADCAST_ENTAS3) + */ + + if (pTask->pWrBuf[0] == CCC_BROADCAST_RSTDAA) { + I3C_DO_RSTDAA(pTaskInfo); + } + + /* + * if (pTask->pWrBuf[0] == CCC_BROADCAST_DEFSLVS) + * if (pTask->pWrBuf[0] == CCC_BROADCAST_SETMWL) + * if (pTask->pWrBuf[0] == CCC_BROADCAST_SETMRL) + * if (pTask->pWrBuf[0] == CCC_BROADCAST_ENTTM) + * if (pTask->pWrBuf[0] == CCC_BROADCAST_SETBUSCON) + * if (pTask->pWrBuf[0] == CCC_BROADCAST_ENDXFER) + * if (pTask->pWrBuf[0] == CCC_BROADCAST_ENTHDR0) + * if (pTask->pWrBuf[0] == CCC_BROADCAST_ENTHDR1) + * if (pTask->pWrBuf[0] == CCC_BROADCAST_ENTHDR2) + * if (pTask->pWrBuf[0] == CCC_BROADCAST_ENTHDR3) + * if (pTask->pWrBuf[0] == CCC_BROADCAST_ENTHDR4) + * if (pTask->pWrBuf[0] == CCC_BROADCAST_ENTHDR5) + * if (pTask->pWrBuf[0] == CCC_BROADCAST_ENTHDR6) + * if (pTask->pWrBuf[0] == CCC_BROADCAST_ENTHDR7) + * if (pTask->pWrBuf[0] == CCC_BROADCAST_SETXTIME) + */ + + if (pTask->pWrBuf[0] == CCC_BROADCAST_SETAASA) { + I3C_DO_SETAASA(pTaskInfo); + } + + /* + * if (pTask->pWrBuf[0] == CCC_BROADCAST_RSTACT) + * if (pTask->pWrBuf[0] == CCC_BROADCAST_DEFGRPA) + * if (pTask->pWrBuf[0] == CCC_BROADCAST_RSTGRPA) + * if (pTask->pWrBuf[0] == CCC_BROADCAST_MLANE) + */ + + if (pTask->pWrBuf[0] == CCC_BROADCAST_SETHID) { + I3C_DO_SETHID(pTaskInfo); + } + /* if (pTask->pWrBuf[0] == CCC_BROADCAST_DEVCTRL) */ + + /* I3C_TRANSFER_PROTOCOL_CCCw */ + if (pTask->pWrBuf[0] == CCC_DIRECT_ENEC) { + I3C_DO_ENEC(pTaskInfo); + } + if (pTask->pWrBuf[0] == CCC_DIRECT_DISEC) { + I3C_DO_DISEC(pTaskInfo); + } + + /* + * if (pTask->pWrBuf[0] == CCC_DIRECT_ENTAS0) + * if (pTask->pWrBuf[0] == CCC_DIRECT_ENTAS1) + * if (pTask->pWrBuf[0] == CCC_DIRECT_ENTAS2) + * if (pTask->pWrBuf[0] == CCC_DIRECT_ENTAS3) + **/ + + if (pTask->pWrBuf[0] == CCC_DIRECT_RSTDAA) { + I3C_DO_RSTDAA(pTaskInfo); + } + if (pTask->pWrBuf[0] == CCC_DIRECT_SETDASA) { + I3C_DO_SETDASA(pTaskInfo); + } + + /* + * if (pTask->pWrBuf[0] == CCC_DIRECT_SETNEWDA) + * if (pTask->pWrBuf[0] == CCC_DIRECT_SETMWL) + * if (pTask->pWrBuf[0] == CCC_DIRECT_SETMRL) + * if (pTask->pWrBuf[0] == CCC_DIRECT_ENDXFER) + * if (pTask->pWrBuf[0] == CCC_DIRECT_SETBRGTGT) + * if (pTask->pWrBuf[0] == CCC_DIRECT_SETROUTE) + * if (pTask->pWrBuf[0] == CCC_DIRECT_SETXTIME) + * if (pTask->pWrBuf[0] == CCC_DIRECT_RSTACT) + * if (pTask->pWrBuf[0] == CCC_DIRECT_SETGRPA) + * if (pTask->pWrBuf[0] == CCC_DIRECT_RSTGRPA) + * if (pTask->pWrBuf[0] == CCC_DIRECT_MLANE) + */ + + /* I3C_TRANSFER_PROTOCOL_CCCr */ + /* + * if (pTask->pWrBuf[0] == CCC_DIRECT_GETMWL) + * if (pTask->pWrBuf[0] == CCC_DIRECT_GETMRL) + * if (pTask->pWrBuf[0] == CCC_DIRECT_GETPID) + * if (pTask->pWrBuf[0] == CCC_DIRECT_GETBCR) + * if (pTask->pWrBuf[0] == CCC_DIRECT_GETDCR) + * if (pTask->pWrBuf[0] == CCC_DIRECT_GETSTATUS) + * if (pTask->pWrBuf[0] == CCC_DIRECT_GETACCCR) + * if (pTask->pWrBuf[0] == CCC_DIRECT_GETMXDS) + * if (pTask->pWrBuf[0] == CCC_DIRECT_GETCAPS) + * if (pTask->pWrBuf[0] == CCC_DIRECT_GETXTIME) + */ + } + + /* Indirect Callback, callback defined in create master task */ + if ((pTaskInfo->callback != NULL) && (pTaskInfo->callback != I3C_Master_Callback)) { + pTaskInfo->callback((__u32)pTaskInfo, ErrDetail); + } + + ret = pTaskInfo->result; + I3C_Complete_Task(pTaskInfo); + pBus->pCurrentTask = NULL; + pBus->busState = I3C_BUS_STATE_IDLE; + + xfer->ret = ret; + k_sem_give(&xfer->sem); + return ret; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Callback if meet any one of the following cases + * 1. address nack (device not present) -> stop + * 2. slave tx data not ready for read transfer -> retry -> stop + * 3. slave does not accept cmd/data (ex: ENTDAA -> not implement yet) + * @param [in] pTaskInfo Pointer to the running task + * @return task result + */ +/*------------------------------------------------------------------------------*/ +__u32 I3C_DO_NACK(I3C_TASK_INFO_t *pTaskInfo) +{ + I3C_TRANSFER_TASK_t *pTask; + I3C_DEVICE_INFO_t *pDevice; + I3C_TRANSFER_FRAME_t *pFrame; + I3C_BUS_INFO_t *pBus; + I3C_BUS_STATE_Enum busNextState; + __u32 ret; + + if (pTaskInfo == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + if (pTaskInfo->Port >= I3C_PORT_MAX) { + return I3C_ERR_PARAMETER_INVALID; + } + + pTask = pTaskInfo->pTask; + + if (pTask->frame_idx >= pTask->frame_count) { + return I3C_ERR_PARAMETER_INVALID; + } + + pDevice = &gI3c_dev_node_internal[pTaskInfo->Port]; + + if (pDevice->pOwner == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + + pFrame = &pTask->pFrameList[pTask->frame_idx]; + pBus = pDevice->pOwner; + + ret = I3C_ERR_OK; + + if (pDevice->mode == I3C_DEVICE_MODE_CURRENT_MASTER) { + busNextState = I3C_BUS_STATE_IDLE; + + if ((pFrame->direction == I3C_TRANSFER_DIR_WRITE) && (pTask->frame_idx != 0)) { + ret = I3C_Notify(pTaskInfo); + + /* update busNextState */ + if (pTask->protocol == I3C_TRANSFER_PROTOCOL_CCCb) { + if (pTask->pWrBuf[0] == CCC_BROADCAST_RSTDAA) { + busNextState = I3C_BUS_STATE_INIT; + } else if (pTask->pWrBuf[0] == CCC_BROADCAST_SETHID) { + busNextState = I3C_BUS_STATE_INIT; + } else if (pTask->pWrBuf[0] == CCC_BROADCAST_SETAASA) { + busNextState = I3C_BUS_STATE_INIT; + } + } else if (pTask->protocol == I3C_TRANSFER_PROTOCOL_CCCw) { + if (pTask->pWrBuf[0] == CCC_DIRECT_SETDASA) { + busNextState = I3C_BUS_STATE_INIT; + } + } + + I3C_Complete_Task(pTaskInfo); + pBus->pCurrentTask = NULL; + pBus->busState = busNextState; + return ret; + } + + /* task not success, but we should not retry it again */ + if (((pFrame->flag & I3C_TRANSFER_RETRY_ENABLE) == 0) + || (pFrame->retry_count == 0)) { + if (pTask->protocol == I3C_TRANSFER_PROTOCOL_ENTDAA) { + return I3C_DO_ENTDAA(pTaskInfo); + } + + I3C_Notify(pTaskInfo); + I3C_Complete_Task(pTaskInfo); + pBus->pCurrentTask = NULL; + pBus->busState = I3C_BUS_STATE_IDLE; + return I3C_ERR_NACK; + } + + /* task not success, but we will retry it again */ + pFrame->retry_count--; + pTaskInfo->result = I3C_ERR_PENDING; + ret = I3C_ERR_PENDING; + + if (pTask->protocol == I3C_TRANSFER_PROTOCOL_ENTDAA) { + pFrame->flag |= I3C_TRANSFER_REPEAT_START; + I3C_Master_Start_Request((__u32)pTaskInfo); + } + } else if ((pDevice->mode == I3C_DEVICE_MODE_SLAVE_ONLY) || + (pDevice->mode == I3C_DEVICE_MODE_SECONDARY_MASTER)) { + /* TODO: retry if not disabled */ + } + + return ret; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Callback when slave nack I2C write is happened + * 1. Try to update read only register in I2C mode + * 2. Try to access I3C device with I2C write transfer + * @param [in] pTaskInfo Pointer to the running task + * @return task result + */ +/*------------------------------------------------------------------------------*/ +__u32 I3C_DO_WRABT(I3C_TASK_INFO_t *pTaskInfo) +{ + I3C_DEVICE_INFO_t *pDevice; + + if (pTaskInfo == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + if (pTaskInfo->Port >= I3C_PORT_MAX) { + return I3C_ERR_PARAMETER_INVALID; + } + + pDevice = &gI3c_dev_node_internal[pTaskInfo->Port]; + if (pDevice->pOwner == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + + /* I3C_Notify(pTaskInfo); */ + return I3C_ERR_OK; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Callback when SLVSTART is happened and not to retry again + * @param [in] pTaskInfo Pointer to the running task + * @return task result + */ +/*------------------------------------------------------------------------------*/ +__u32 I3C_DO_SLVSTART(I3C_TASK_INFO_t *pTaskInfo) +{ + I3C_TRANSFER_TASK_t *pTask; + I3C_TRANSFER_FRAME_t *pFrame; + I3C_DEVICE_INFO_t *pDevice; + I3C_BUS_INFO_t *pBus; + + if (pTaskInfo == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + if (pTaskInfo->Port >= I3C_PORT_MAX) { + return I3C_ERR_PARAMETER_INVALID; + } + + pTask = pTaskInfo->pTask; + + if (pTask->frame_idx >= pTask->frame_count) { + return I3C_ERR_PARAMETER_INVALID; + } + + pFrame = &pTask->pFrameList[pTask->frame_idx]; + pDevice = &gI3c_dev_node_internal[pTaskInfo->Port]; + pBus = pDevice->pOwner; + + if (((pFrame->flag & I3C_TRANSFER_RETRY_ENABLE) == 0) || (pFrame->retry_count == 0)) { + I3C_Notify(pTaskInfo); + return pTaskInfo->result; + } + + pFrame->retry_count--; + pTaskInfo->result = I3C_ERR_PENDING; + pBus->pCurrentTask = NULL; + return I3C_ERR_OK; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Callback when timeout is happened + * @param [in] pTaskInfo Pointer to the running task + * @return task result + */ +/*------------------------------------------------------------------------------*/ +__u32 I3C_DO_SW_TIMEOUT(I3C_TASK_INFO_t *pTaskInfo) +{ + I3C_TRANSFER_TASK_t *pTask; + I3C_DEVICE_INFO_t *pDevice; + I3C_BUS_INFO_t *pBus; + __u32 ret; + + if (pTaskInfo == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + if (pTaskInfo->pTask == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + if (pTaskInfo->Port >= I3C_PORT_MAX) { + return I3C_ERR_PARAMETER_INVALID; + } + + pTask = pTaskInfo->pTask; + pDevice = &gI3c_dev_node_internal[pTaskInfo->Port]; + pBus = pDevice->pOwner; + + ret = I3C_Notify(pTaskInfo); + if (ret == 0) { + I3C_Complete_Task(pTaskInfo); + FreeTaskNode(pTask); + pBus->pCurrentTask = NULL; + return I3C_ERR_OK; + } + + return ret; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Callback when IBI is happened + * @param [in] pTaskInfo Pointer to the running task + * @return task result + */ +/*------------------------------------------------------------------------------*/ +__u32 I3C_DO_IBI(I3C_TASK_INFO_t *pTaskInfo) +{ + I3C_TRANSFER_TASK_t *pTask; + I3C_BUS_INFO_t *pBus; + I3C_DEVICE_INFO_SHORT_t *pDev; + + if (pTaskInfo == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + if (pTaskInfo->pTask == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + if (pTaskInfo->Port >= I3C_PORT_MAX) { + return I3C_ERR_PARAMETER_INVALID; + } + + pTask = pTaskInfo->pTask; + pBus = Get_Bus_From_Port(pTaskInfo->Port); + pDev = GetDevInfoByDynamicAddr(pBus, pTask->address); + if (pDev == NULL) { + return I3C_ERR_TASK_INVALID; + } + + if (pTaskInfo->callback != NULL) { + /* pTaskInfo->callback(TaskInfo, ErrDetail); */ + } + + I3C_Complete_Task(pTaskInfo); + pBus->pCurrentTask = NULL; + pBus->busState = I3C_BUS_STATE_IDLE; + return I3C_ERR_OK; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Callback when Hot Join is happened + * @param [in] pTaskInfo Pointer to the running task + * @return task result + */ +/*------------------------------------------------------------------------------*/ +__u32 I3C_DO_HOT_JOIN(I3C_TASK_INFO_t *pTaskInfo) +{ + I3C_TRANSFER_TASK_t *pTask; + I3C_DEVICE_INFO_t *pDevice; + I3C_BUS_INFO_t *pBus; + I3C_TRANSFER_FRAME_t *pFrame; + + if (pTaskInfo == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + if (pTaskInfo->pTask == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + if (pTaskInfo->Port >= I3C_PORT_MAX) { + return I3C_ERR_PARAMETER_INVALID; + } + + pTask = pTaskInfo->pTask; + pDevice = &gI3c_dev_node_internal[pTaskInfo->Port]; + + if (pDevice->pOwner == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + + pBus = pDevice->pOwner; + pFrame = &pTask->pFrameList[pTask->frame_idx]; + + if (((pFrame->flag & I3C_TRANSFER_RETRY_ENABLE) == 0) || (pFrame->retry_count == 0)) { + I3C_Notify(pTaskInfo); + return pTaskInfo->result; + } + + pFrame->retry_count--; + pTaskInfo->result = I3C_ERR_PENDING; + pBus->pCurrentTask = NULL; + + return I3C_ERR_OK; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Callback when Master Request is happened + * @param [in] pTaskInfo Pointer to the running task + * @return task result + */ +/*------------------------------------------------------------------------------*/ +__u32 I3C_DO_MASTER_REQUEST(I3C_TASK_INFO_t *pTaskInfo) +{ + I3C_BUS_INFO_t *pBus; + + if (pTaskInfo == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + if (pTaskInfo->Port >= I3C_PORT_MAX) { + return I3C_ERR_PARAMETER_INVALID; + } + + pBus = Get_Bus_From_Port(pTaskInfo->Port); + + /* we can't control the external slave device which will change to current master */ + /* we will update the internal slave device in slave's callback */ + + I3C_Complete_Task(pTaskInfo); + pBus->pCurrentTask = NULL; + pBus->busState = I3C_BUS_STATE_IDLE; + + return I3C_ERR_OK; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Callback when slave ack ENEC task + * @param [in] pTaskInfo Pointer to the running task + * @return task result + */ +/*------------------------------------------------------------------------------*/ +__u32 I3C_DO_ENEC(I3C_TASK_INFO_t *pTaskInfo) +{ + I3C_BUS_INFO_t *pBus; + I3C_TRANSFER_TASK_t *pTask; + I3C_TRANSFER_PROTOCOL_Enum protocol; + I3C_DEVICE_INFO_SHORT_t *pDev; + __u8 i; + + if (pTaskInfo == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + if (pTaskInfo->Port >= I3C_PORT_MAX) { + return I3C_ERR_PARAMETER_INVALID; + } + if (pTaskInfo->pTask == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + if (pTaskInfo->pTask->pWrBuf == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + + pBus = Get_Bus_From_Port(pTaskInfo->Port); + pTask = pTaskInfo->pTask; + protocol = pTask->protocol; + + if (protocol == I3C_TRANSFER_PROTOCOL_CCCb) { + pDev = pBus->pDevList; + + while (pDev != NULL) + pDev = pDev->pNextDev; + } else { + for (i = 1; i <= pTask->frame_idx; i++) { + pDev = GetDevInfoByDynamicAddr(pBus, pTask->pFrameList[i].address); + if (pDev == NULL) { + continue; + } + } + } + + return I3C_ERR_OK; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Callback when slave ack DISEC task + * @param [in] pTaskInfo Pointer to the running task + * @return task result + */ +/*------------------------------------------------------------------------------*/ +__u32 I3C_DO_DISEC(I3C_TASK_INFO_t *pTaskInfo) +{ + return I3C_DO_ENEC(pTaskInfo); +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Callback when slave ack RSTDAA task + * @param [in] pTaskInfo Pointer to the running task + * @return task result + */ +/*------------------------------------------------------------------------------*/ +__u32 I3C_DO_RSTDAA(I3C_TASK_INFO_t *pTaskInfo) +{ + I3C_DEVICE_INFO_t *pDevice; + I3C_BUS_INFO_t *pBus; + I3C_DEVICE_INFO_SHORT_t *pDev; + + if (pTaskInfo == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + if (pTaskInfo->Port >= I3C_PORT_MAX) { + return I3C_ERR_PARAMETER_INVALID; + } + + pDevice = &gI3c_dev_node_internal[pTaskInfo->Port]; + pBus = pDevice->pOwner; + pDev = pBus->pDevList; + + while (pDev != NULL) { + if (pDev->attr.b.present) { + if (IS_Internal_DEVICE(pDev->pDeviceInfo)) { + pDevice = (I3C_DEVICE_INFO_t *)pDev->pDeviceInfo; + + if ((pDevice->mode == I3C_DEVICE_MODE_CURRENT_MASTER) + || (pDevice->mode == I3C_DEVICE_MODE_DISABLE)) { + pDev = pDev->pNextDev; + continue; + } + + pDevice->bRunI3C = FALSE; + pDevice->dynamicAddr = I3C_DYNAMIC_ADDR_DEFAULT_7BIT; + pDevice->ackIBI = FALSE; + I3C_Clean_Slave_Task(pDevice); + } + + pDev->attr.b.runI3C = 0; + pDev->dynamicAddr = I3C_DYNAMIC_ADDR_DEFAULT_7BIT; + if ((pDev->attr.b.reqRSTDAA) && (pDev->attr.b.doneRSTDAA == 0)) { + pDev->attr.b.doneRSTDAA = 1; + } + } + + pDev = pDev->pNextDev; + } + + return I3C_ERR_OK; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Callback when slave ack ENTDAA task + * @param [in] pTaskInfo Pointer to the running task + * @return task result + */ +/*------------------------------------------------------------------------------*/ +__u32 I3C_DO_ENTDAA(I3C_TASK_INFO_t *pTaskInfo) +{ + I3C_TRANSFER_TASK_t *pTask; + I3C_BUS_INFO_t *pBus; + I3C_DEVICE_INFO_SHORT_t *pDev; + I3C_DEVICE_INFO_t *pDevice; + + __u8 i; + __u8 *pid; + __u8 bcr; + __u8 dcr; + __u8 dyn_addr; + + if (pTaskInfo == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + if (pTaskInfo->pTask == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + if (pTaskInfo->Port >= I3C_PORT_MAX) { + return I3C_ERR_PARAMETER_INVALID; + } + + pTask = pTaskInfo->pTask; + pBus = Get_Bus_From_Port(pTaskInfo->Port); + if (pBus == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + + for (i = 1; i <= pTask->frame_idx; i++) { + pid = pTask->pFrameList[pTask->frame_idx].access_buf; + bcr = pTask->pFrameList[pTask->frame_idx].access_buf[6]; + dcr = pTask->pFrameList[pTask->frame_idx].access_buf[7]; + dyn_addr = pTask->pFrameList[pTask->frame_idx].access_buf[8]; + + pDev = pBus->pDevList; + while (pDev != NULL) { + if (IS_Internal_DEVICE(pDev->pDeviceInfo)) { + pDevice = pDev->pDeviceInfo; + + if ((pDev->bcr == bcr) && (pDev->dcr == dcr) + && (((pDevice->mode == I3C_DEVICE_MODE_SLAVE_ONLY) + || (pDevice->mode == + I3C_DEVICE_MODE_SECONDARY_MASTER)) + && (hal_i3c_get_dynamic_address( + pDevice->port) == dyn_addr))) { + pDevice->bRunI3C = TRUE; + pDevice->dynamicAddr = dyn_addr; + + if (((pDev->bcr & 0x06) == 0x02) + || ((pDev->bcr & 0x06) == 0x06)) { + pDevice->ackIBI = TRUE; + } else { + pDevice->ackIBI = FALSE; + } + + pDev->attr.b.runI3C = 1; + pDev->dynamicAddr = dyn_addr; + break; + } + } else { + if ((pDev->bcr == bcr) && (pDev->dcr == dcr) + && (memcmp(pDev->pid, pid, 6) == 0)) { + pDev->attr.b.runI3C = 1; + pDev->dynamicAddr = dyn_addr; + break; + } + } + + pDev = pDev->pNextDev; + } + } + + if (pTaskInfo->result == I3C_ERR_MEMORY_RAN_OUT) { + /* reuse task to do ENTDAA again */ + pTask->frame_idx = 0; + I3C_Master_Start_Request((__u32)pTaskInfo); + return I3C_ERR_OK; + } + + if (pTaskInfo->result == I3C_ERR_NACK) { + /* slave reject address, reuse this task to retry again */ + /* after we release address with higher priority */ + pTask->frame_idx = 0; + } + + /* Remove from master's task */ + return I3C_ERR_OK; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Callback when slave ack SETAASA task + * @param [in] pTaskInfo Pointer to the running task + * @return task result + */ +/*------------------------------------------------------------------------------*/ +__u32 I3C_DO_SETAASA(I3C_TASK_INFO_t *pTaskInfo) +{ + I3C_DEVICE_INFO_t *pDevice; + I3C_BUS_INFO_t *pBus; + I3C_DEVICE_INFO_SHORT_t *pDev; + + if (pTaskInfo == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + if (pTaskInfo->Port >= I3C_PORT_MAX) { + return I3C_ERR_PARAMETER_INVALID; + } + + pDevice = &gI3c_dev_node_internal[pTaskInfo->Port]; + pBus = pDevice->pOwner; + pDev = pBus->pDevList; + + while (pDev != NULL) { + pDev = pDev->pNextDev; + } + + /* Remove from master's task */ + pBus->pCurrentTask = NULL; + pBus->busState = I3C_BUS_STATE_INIT; + return I3C_ERR_OK; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Callback when slave ack SETHID task + * @param [in] pTaskInfo Pointer to the running task + * @return task result + */ +/*------------------------------------------------------------------------------*/ +__u32 I3C_DO_SETHID(I3C_TASK_INFO_t *pTaskInfo) +{ + I3C_DEVICE_INFO_t *pDevice; + I3C_BUS_INFO_t *pBus; + I3C_DEVICE_INFO_SHORT_t *pDev; + __u32 result; + + if (pTaskInfo == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + if (pTaskInfo->Port >= I3C_PORT_MAX) { + return I3C_ERR_PARAMETER_INVALID; + } + + pDevice = &gI3c_dev_node_internal[pTaskInfo->Port]; + pBus = pDevice->pOwner; + pDev = pBus->pDevList; + result = pTaskInfo->result; + + while (pDev != NULL) { + pDev = pDev->pNextDev; + } + + return result; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Callback when slave ack SETDASA task + * @param [in] pTaskInfo Pointer to the running task + * @return task result + */ +/*------------------------------------------------------------------------------*/ +__u32 I3C_DO_SETDASA(I3C_TASK_INFO_t *pTaskInfo) +{ + I3C_DEVICE_INFO_t *pDevice; + I3C_BUS_INFO_t *pBus; + I3C_TRANSFER_TASK_t *pTask; + I3C_TRANSFER_FRAME_t *pFrame; + I3C_DEVICE_INFO_SHORT_t *pDev; + __u8 i; + + if (pTaskInfo == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + if (pTaskInfo->pTask == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + if (pTaskInfo->Port >= I3C_PORT_MAX) { + return I3C_ERR_PARAMETER_INVALID; + } + + pDevice = &gI3c_dev_node_internal[pTaskInfo->Port]; + pBus = pDevice->pOwner; + pTask = pTaskInfo->pTask; + + for (i = 1; i < pTask->frame_count; i++) { + pFrame = &pTask->pFrameList[i]; + pDev = GetDevInfoByStaticAddr(pBus, pFrame->address); + + if (pDev->attr.b.present) { + /* SPD5118 does not support SETDASA */ + if (IS_Internal_DEVICE(pDev->pDeviceInfo)) { + pDevice = (I3C_DEVICE_INFO_t *) pDev->pDeviceInfo; + if (pDevice->mode == I3C_DEVICE_MODE_DISABLE) { + continue; + } + if (pDevice->mode == I3C_DEVICE_MODE_CURRENT_MASTER) { + continue; + } + + pDevice->bRunI3C = TRUE; + pDevice->dynamicAddr = pDevice->staticAddr; + pDevice->ackIBI = TRUE; + } + + pDev->attr.b.runI3C = 1; + pDev->dynamicAddr = pDev->staticAddr; + + if ((pDev->attr.b.reqSETDASA) && (pDev->attr.b.doneSETDASA == 0)) { + pDev->attr.b.doneSETDASA = 1; + } + } + } + + return I3C_ERR_OK; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Callback when slave ack SETNEWDA task + * @param [in] pTaskInfo Pointer to the running task + * @return task result + */ +/*------------------------------------------------------------------------------*/ +__u32 I3C_DO_SETNEWDA(I3C_TASK_INFO_t *pTaskInfo) +{ + I3C_TRANSFER_TASK_t *pTask; + I3C_BUS_INFO_t *pBus; + I3C_DEVICE_INFO_t *pDevice; + __u8 i; + I3C_TRANSFER_FRAME_t *pFrame; + I3C_DEVICE_INFO_SHORT_t *pDev; + + if (pTaskInfo == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + if (pTaskInfo->pTask == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + if (pTaskInfo->Port >= I3C_PORT_MAX) { + return I3C_ERR_PARAMETER_INVALID; + } + + pTask = pTaskInfo->pTask; + pBus = Get_Bus_From_Port(pTaskInfo->Port); + if (pBus->pCurrentMaster == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + + pDevice = pBus->pCurrentMaster; + for (i = 1; i < pTask->frame_count; i++) { + pFrame = &pTask->pFrameList[i]; + pDev = GetDevInfoByDynamicAddr(pBus, pFrame->address); + + if (pDev->attr.b.present) { + /* SPD5118 doesn't support SETNEWDA */ + if (IS_Internal_DEVICE(pDev->pDeviceInfo)) { + pDevice = (I3C_DEVICE_INFO_t *)pDev->pDeviceInfo; + if (pDevice->mode == I3C_DEVICE_MODE_DISABLE) { + continue; + } + if (pDevice->mode == I3C_DEVICE_MODE_CURRENT_MASTER) { + continue; + } + + pDevice->dynamicAddr = pFrame->access_buf[0]; + pDev->dynamicAddr = pFrame->access_buf[0]; + } + } + } + + return I3C_ERR_OK; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Start to run master's task + * @param [in] Parm Pointer to task + * @return none + */ +/*------------------------------------------------------------------------------*/ +void I3C_Master_Start_Request(__u32 Parm) +{ + I3C_TASK_INFO_t *pTaskInfo; + I3C_BUS_INFO_t *pBus; + I3C_TRANSFER_TASK_t *pTask; + I3C_TRANSFER_PROTOCOL_Enum protocol; + + if (Parm == 0) { + return; + } + + pTaskInfo = (I3C_TASK_INFO_t *)Parm; + if (pTaskInfo->pTask == NULL) { + return; + } + + pBus = Get_Bus_From_Port(pTaskInfo->Port); + pTask = pTaskInfo->pTask; + protocol = pTask->protocol; + + if (I3C_IS_BUS_DETECT_SLVSTART(pBus)) { + /* try to run master's task but SLVSTART is happened, + * and we should process it with higher priority + * abort current task and Event task will be inserted in ISR + */ + if (protocol != I3C_TRANSFER_PROTOCOL_EVENT) { + pBus->pCurrentTask = NULL; + return; + } + + hal_I3C_Process_Task(pTaskInfo); + } else if (I3C_IS_BUS_DURING_DAA(pBus)) { + if (protocol != I3C_TRANSFER_PROTOCOL_ENTDAA) { + return; + } + hal_I3C_Process_Task(pTaskInfo); + } else if (I3C_IS_BUS_WAIT_STOP_OR_RETRY(pBus)) { + hal_I3C_Process_Task(pTaskInfo); + } else { + hal_I3C_Master_Stall(pBus, pTaskInfo->Port); + + if (I3C_IS_BUS_DETECT_SLVSTART(pBus) && (protocol != I3C_TRANSFER_PROTOCOL_EVENT)) { + pBus->pCurrentTask = NULL; + return; + } + + hal_I3C_Process_Task(pTaskInfo); + } +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief generate STOP then callback + * @param [in] Parm Pointer to task + * @return none + */ +/*------------------------------------------------------------------------------*/ +void I3C_Master_Stop_Request(__u32 Parm) +{ + I3C_TRANSFER_TASK_t *pTask; + I3C_TASK_INFO_t *pTaskInfo; + __u8 port; + + if (Parm == 0) { + return; + } + + pTask = (I3C_TRANSFER_TASK_t *) Parm; + if (pTask->pTaskInfo == NULL) { + return; + } + + pTaskInfo = pTask->pTaskInfo; + if (pTaskInfo->Port >= I3C_PORT_MAX) { + return; + } + + port = pTaskInfo->Port; + + if (pTaskInfo->result == I3C_ERR_IBI) { + pTask->address = hal_I3C_get_ibiAddr(port); + } + + I3C_Master_Callback((uint32_t) pTaskInfo, pTaskInfo->result); + hal_I3C_Stop(port); +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Finish master task + * @param [in] Parm Pointer to task + * @return none + */ +/*------------------------------------------------------------------------------*/ +void I3C_Master_End_Request(__u32 Parm) +{ + I3C_TRANSFER_TASK_t *pTask; + I3C_TASK_INFO_t *pTaskInfo; + + if (Parm == 0) { + return; + } + + pTask = (I3C_TRANSFER_TASK_t *) Parm; + if (pTask->pTaskInfo == NULL) { + return; + } + + pTaskInfo = pTask->pTaskInfo; + + I3C_Master_Callback((__u32)pTaskInfo, pTaskInfo->result); +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Keep running next frame of the master task + * @param [in] Parm Pointer to task + * @return none + */ +/*------------------------------------------------------------------------------*/ +#define MACRO pTask->pFrameList[pTask->frame_idx + 1].access_buf[8] = pDev->staticAddr; + +void I3C_Master_Run_Next_Frame(__u32 Parm) +{ + I3C_TRANSFER_TASK_t *pTask; + I3C_TASK_INFO_t *pTaskInfo; + I3C_BUS_INFO_t *pBus; + I3C_DEVICE_INFO_SHORT_t *pDev; + __u8 pid[6]; + __u8 bcr; + __u8 dcr; + I3C_DEVICE_INFO_t *pDevice; + + + if (Parm == 0) { + return; + } + + pTask = (I3C_TRANSFER_TASK_t *)Parm; + if (pTask->pTaskInfo == NULL) { + return; + } + if (pTask->frame_idx >= pTask->frame_count) { + return; + } + + pTaskInfo = pTask->pTaskInfo; + if (pTaskInfo->Port >= I3C_PORT_MAX) { + return; + } + + if (pTask->protocol == I3C_TRANSFER_PROTOCOL_ENTDAA) { + pBus = Get_Bus_From_Port(pTaskInfo->Port); + + /* previous slave dynamic address has been accepted, if (pTask->frame_idx != 0) + * we will process them in the ENTDAA's callback + * + * Now, we try to assign slave dynamic address in according to PID, BCR, DCR and + * save the into access_buf[8] + */ + memcpy(pid, pTask->pFrameList[pTask->frame_idx + 1].access_buf, 6); + bcr = pTask->pFrameList[pTask->frame_idx + 1].access_buf[6]; + dcr = pTask->pFrameList[pTask->frame_idx + 1].access_buf[7]; + + pDev = pBus->pDevList; + while (pDev != NULL) { + if ((pDev->attr.b.present) && (!IsValidDynamicAddress(pDev->dynamicAddr)) + && (pDev->bcr == bcr) && (pDev->dcr == dcr) + && (memcmp(pDev->pid, pid, 6) == 0)) { + if (IS_Internal_DEVICE(pDev->pDeviceInfo)) { + pDevice = pDev->pDeviceInfo; + + if ((pDevice->mode == I3C_DEVICE_MODE_SLAVE_ONLY) + || (pDevice->mode + == I3C_DEVICE_MODE_SECONDARY_MASTER)) { + MACRO; + break; + } + + pDev = pDev->pNextDev; + continue; + } + + /* adopt user define in advance */ + MACRO; + break; + } + + pDev = pDev->pNextDev; + } + } +#undef ASSIGN_NEW_ADDRESS + + pTask->frame_idx++; + I3C_Master_Start_Request((__u32)pTaskInfo); +} +#undef MACRO + +/*------------------------------------------------------------------------------*/ +/** + * @brief Insert event task to handle slave request + * @param [in] Parm i3c master detect the SLVSTART + * @return none + */ +/*------------------------------------------------------------------------------*/ +void I3C_Master_New_Request(__u32 Parm) +{ + __u8 port; + I3C_BUS_INFO_t *pBus; + I3C_TRANSFER_TASK_t *pTask; + I3C_TASK_INFO_t *pTaskInfo; + + if (Parm >= I3C_PORT_MAX) { + return; + } + + port = (__u8)Parm; + I3C_Master_Insert_Task_EVENT(IBI_PAYLOAD_SIZE_MAX, NULL, I3C_TRANSFER_SPEED_SDR_IBI, + TIMEOUT_TYPICAL, I3C_Master_Callback, port, I3C_TASK_POLICY_INSERT_FIRST, NOT_HIF); + + pBus = Get_Bus_From_Port(port); + if (pBus == NULL) { + return; + } + if (pBus->pCurrentMaster == NULL) { + return; + } + if (pBus->pCurrentMaster->pTaskListHead == NULL) { + return; + } + + pTask = pBus->pCurrentMaster->pTaskListHead; + if (pTask->pTaskInfo == NULL) { + return; + } + + pTaskInfo = pTask->pTaskInfo; + pBus->pCurrentTask = pTask; + pBus->busState = I3C_BUS_STATE_IDLE; + I3C_Master_Start_Request((__u32)pTaskInfo); +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Insert DISEC task to disable slave request + * @param [in] Parm Pointer to task + * @return none + */ +/*------------------------------------------------------------------------------*/ +void I3C_Master_Insert_DISEC_After_IbiNack(__u32 Parm) +{ + I3C_TRANSFER_TASK_t *pTask; + I3C_TASK_INFO_t *pTaskInfo; + __u8 port; + I3C_BUS_INFO_t *pBus; + I3C_IBITYPE_Enum ibiType; + __u8 ibiAddress; + I3C_DEVICE_INFO_t *pDevice; + I3C_TRANSFER_FRAME_t *pFrame; + + if (Parm == 0) { + return; + } + + pTask = (I3C_TRANSFER_TASK_t *) Parm; + if (pTask->pTaskInfo == NULL) { + return; + } + + pTaskInfo = pTask->pTaskInfo; + if (pTaskInfo->Port >= I3C_PORT_MAX) { + return; + } + + port = pTaskInfo->Port; + pBus = Get_Bus_From_Port(port); + + ibiType = hal_I3C_get_ibiType(port); + ibiAddress = hal_I3C_get_ibiAddr(port); + + if (pTask->protocol == I3C_TRANSFER_PROTOCOL_EVENT) { + pTaskInfo->result = I3C_ERR_OK; + *pTask->pRdLen = 0; + I3C_Master_Callback((uint32_t) pTaskInfo, pTaskInfo->result); + } + + /* Reset DMA and FIFO before IBIAckNack */ + hal_I3C_Disable_Master_DMA(port); + hal_I3C_Reset_Master_TX(port); /* reset Tx FIFO, for HDRCMD */ + hal_I3C_Nack_IBI(port); + + if (ibiAddress == 0x00) { + /* Used to patch SPD5118's abnormal behavior + * Bus master try to ENTDAA but SPD5118 has already been in I3C mode + */ + I3C_CCCb_DISEC(pBus, DISEC_MASK_ENINT, I3C_TASK_POLICY_INSERT_FIRST); + } else if (ibiType == I3C_IBITYPE_HotJoin) { + /* It must be broadcast CCC, because slave doesn't have dynamic addrerss yet */ + I3C_CCCb_DISEC(pBus, DISEC_MASK_ENHJ, I3C_TASK_POLICY_INSERT_FIRST); + } else if (ibiType == I3C_IBITYPE_IBI) { + I3C_CCCw_DISEC(pBus, ibiAddress, DISEC_MASK_ENINT, I3C_TASK_POLICY_INSERT_FIRST); + } else if (ibiType == I3C_IBITYPE_MstReq) { + I3C_CCCw_DISEC(pBus, ibiAddress, DISEC_MASK_ENMR, I3C_TASK_POLICY_INSERT_FIRST); + } + + /* run the DISEC immediatedly */ + if (pBus->pCurrentMaster == NULL) { + return; + } + + pDevice = pBus->pCurrentMaster; + if (pDevice->pTaskListHead == NULL) { + return; + } + + pTask = pDevice->pTaskListHead; + if (pTask->pTaskInfo == NULL) { + return; + } + + pTaskInfo = pTask->pTaskInfo; + if (pTask->frame_idx >= pTask->frame_count) { + return; + } + + pFrame = &pTask->pFrameList[pTask->frame_idx]; + pFrame->flag |= I3C_TRANSFER_REPEAT_START; + pBus->pCurrentTask = pTask; + I3C_Master_Start_Request((__u32)pTaskInfo); +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Ack the IBI + * @param [in] Parm Pointer to task + * @return none + */ +/*------------------------------------------------------------------------------*/ +void I3C_Master_IBIACK(__u32 Parm) +{ + I3C_TRANSFER_TASK_t *pTask; + I3C_TASK_INFO_t *pTaskInfo; + I3C_PORT_Enum port; + I3C_DEVICE_INFO_t *pDevice; + I3C_BUS_INFO_t *pBus; + uint8_t ibiAddress; + I3C_DEVICE_INFO_SHORT_t *pSlvDev; + + if (Parm == 0) { + return; + } + + pTask = (I3C_TRANSFER_TASK_t *)Parm; + if (pTask->pTaskInfo == NULL) { + return; + } + + pTaskInfo = pTask->pTaskInfo; + port = pTaskInfo->Port; + + pDevice = I3C_Get_INODE(port); + if (pDevice->pOwner == NULL) { + return; + } + + pBus = pDevice->pOwner; + if (pTask->protocol != I3C_TRANSFER_PROTOCOL_EVENT) { + hal_I3C_Disable_Master_RX_DMA(port); + + /* Insert Event task and assume event task has running to + * restore IBI Type and IBI address + */ + I3C_Master_Insert_Task_EVENT(IBI_PAYLOAD_SIZE_MAX, NULL, + I3C_TRANSFER_SPEED_SDR_IBI, TIMEOUT_TYPICAL, I3C_Master_Callback, + port, I3C_TASK_POLICY_INSERT_FIRST, NOT_HIF); + + if (pDevice->pTaskListHead == NULL) { + return; + } + + pTask = pDevice->pTaskListHead; + pBus->pCurrentTask = pTask; + + if (pTask->pTaskInfo == NULL) { + return; + } + pTaskInfo = pTask->pTaskInfo; + } + + ibiAddress = hal_I3C_get_ibiAddr(port); + + pSlvDev = GetDevInfoByDynamicAddr(pBus, ibiAddress); + if (pSlvDev == NULL) { + /* slave device info should be init after + * ENTDAA/SETAASA/SETDASA/SETNEWDA + */ + } else { + if ((pSlvDev->bcr & 0x06) == 0x06) { + hal_I3C_Ack_IBI_With_MDB(port); + } else if ((pSlvDev->bcr & 0x06) == 0x02) { + hal_I3C_Ack_IBI_Without_MDB(port); + hal_I3C_Disable_Master_RX_DMA(port); + pTaskInfo->result = I3C_ERR_OK; + *pTask->pRdLen = 0; + } + } +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief ack the Master Request, then insert GETACCMST task + * @param [in] Parm Pointer to task + * @return none + */ +/*------------------------------------------------------------------------------*/ +void I3C_Master_Insert_GETACCMST_After_IbiAckMR(__u32 Parm) +{ + I3C_TRANSFER_TASK_t *pTask; + I3C_TASK_INFO_t *pTaskInfo; + uint8_t port; + uint8_t ibiAddress; + I3C_BUS_INFO_t *pBus; + I3C_DEVICE_INFO_SHORT_t *pDev; + I3C_TRANSFER_FRAME_t *pFrame; + __u8 wrBuf[2]; + __u8 *rdBuf; + + if (Parm == 0) { + return; + } + + pTask = (I3C_TRANSFER_TASK_t *)Parm; + + if (pTask->pTaskInfo == NULL) { + return; + } + pTaskInfo = pTask->pTaskInfo; + + if (pTaskInfo->Port >= I3C_PORT_MAX) { + return; + } + port = pTaskInfo->Port; + + + hal_I3C_Ack_IBI_Without_MDB(port); + hal_I3C_Disable_Master_RX_DMA(port); + + pTaskInfo->result = I3C_ERR_MR; + *pTask->pRdLen = 0; + I3C_Master_Callback((uint32_t) pTaskInfo, pTaskInfo->result); + + ibiAddress = hal_I3C_get_ibiAddr(port); + + /* Ack the Master-Request --> IBIWON and COMPLETE will set again */ + /* Insert GETACCMST and let GETACCMST start with RESTART */ + pBus = Get_Bus_From_Port(port); + pDev = NULL; + pDev = GetDevInfoByDynamicAddr(pBus, ibiAddress); + if (pDev == NULL) { + return; + } + + rdBuf = hal_I3C_MemAlloc(1); + wrBuf[0] = ibiAddress; + I3C_Master_Insert_Task_CCCr(CCC_DIRECT_GETACCMST, 1, 1, 1, wrBuf, rdBuf, + I3C_TRANSFER_SPEED_SDR_IBI, TIMEOUT_TYPICAL, + I3C_Master_Callback, port, I3C_TASK_POLICY_INSERT_FIRST, IS_HIF); + + pTask = pBus->pCurrentMaster->pTaskListHead; + pTaskInfo = pTask->pTaskInfo; + pFrame = &pTask->pFrameList[pTask->frame_idx]; + pFrame->flag |= I3C_TRANSFER_REPEAT_START; + I3C_Master_Start_Request((uint32_t) pTaskInfo); +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief ack the Hot Join, then insert ENTDAA task + * @param [in] Parm Pointer to task + * @return none + */ +/*------------------------------------------------------------------------------*/ +void I3C_Master_Insert_ENTDAA_After_IbiAckHJ(__u32 Parm) +{ + I3C_TRANSFER_TASK_t *pTask; + I3C_TASK_INFO_t *pTaskInfo; + __u8 port; + + + if (Parm == 0) { + return; + } + + pTask = (I3C_TRANSFER_TASK_t *)Parm; + + if (pTask->pTaskInfo == NULL) { + return; + } + + pTaskInfo = pTask->pTaskInfo; + + if (pTaskInfo->Port >= I3C_PORT_MAX) { + return; + } + + port = pTaskInfo->Port; + + pTaskInfo->result = I3C_ERR_OK; + *pTask->pRdLen = 0; + + hal_I3C_Disable_Master_RX_DMA(port); + hal_I3C_Ack_IBI_Without_MDB(port); + + /* Must to use STOP to notify slave finish hot-join task + * Can't use RESTART + ENTDAA, that will cause MERRWARN.INVREQ + */ + I3C_Master_Stop_Request((__u32)pTask); + I3C_Master_Insert_Task_ENTDAA(63, NULL, I3C_TRANSFER_SPEED_SDR_1MHZ, TIMEOUT_TYPICAL, + NULL, port, I3C_TASK_POLICY_INSERT_FIRST, NOT_HIF); +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief configure PDMA for master write transfer + * @param [in] pDevice Pointer to device object + * @return none + */ +/*------------------------------------------------------------------------------*/ +I3C_ErrCode_Enum Setup_Master_Write_DMA(I3C_DEVICE_INFO_t *pDevice) +{ + I3C_TRANSFER_TASK_t *pTask; + I3C_TRANSFER_FRAME_t *pFrame; + + + if (pDevice == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + if (pDevice->port >= I3C_PORT_MAX) { + return I3C_ERR_TASK_INVALID; + } + if (pDevice->pTaskListHead == NULL) { + return I3C_ERR_TASK_INVALID; + } + + pTask = pDevice->pTaskListHead; + if (pTask->frame_idx >= pTask->frame_count) { + return I3C_ERR_TASK_INVALID; + } + + pFrame = &pTask->pFrameList[pTask->frame_idx]; + if ((pFrame->access_len - pFrame->access_idx) == 0) { + return I3C_ERR_OK; + } + + hal_I3C_DMA_Write(pDevice->port, pDevice->mode, &pFrame->access_buf[pFrame->access_idx], + pFrame->access_len - pFrame->access_idx); + pFrame->access_idx = pFrame->access_len; + + return I3C_ERR_OK; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief configure PDMA for master read transfer + * @param [in] pDevice Pointer to device object + * @return none + */ +/*------------------------------------------------------------------------------*/ +I3C_ErrCode_Enum Setup_Master_Read_DMA(I3C_DEVICE_INFO_t *pDevice) +{ + I3C_TRANSFER_TASK_t *pTask; + I3C_TRANSFER_FRAME_t *pFrame; + + if (pDevice == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + if (pDevice->port >= I3C_PORT_MAX) { + return I3C_ERR_TASK_INVALID; + } + if (pDevice->pTaskListHead == NULL) { + return I3C_ERR_TASK_INVALID; + } + + pTask = pDevice->pTaskListHead; + + if (pTask->frame_idx >= pTask->frame_count) { + return I3C_ERR_TASK_INVALID; + } + + pFrame = &pTask->pFrameList[pTask->frame_idx]; + + if ((pFrame->access_len - pFrame->access_idx) == 0) { + return I3C_ERR_OK; + } + + hal_I3C_DMA_Read(pDevice->port, pDevice->mode, &pFrame->access_buf[pFrame->access_idx], + pFrame->access_len - pFrame->access_idx); + return I3C_ERR_OK; +} diff --git a/drivers/i3c/NPCM4XX/i3c_slave.c b/drivers/i3c/NPCM4XX/i3c_slave.c new file mode 100644 index 00000000000000..50f340ce9da973 --- /dev/null +++ b/drivers/i3c/NPCM4XX/i3c_slave.c @@ -0,0 +1,405 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +I3C_REG_ITEM_t *pSlaveReg[I3C_PORT_MAX] = { NULL, NULL }; + +/*------------------------------------------------------------------------------*/ +/** + * @brief Callback for I3C slave + * @param [in] TaskInfo Pointer to the running task + * @param [in] ErrDetail task result + * @return final task result + */ +/*------------------------------------------------------------------------------*/ +__u32 I3C_Slave_Callback(__u32 TaskInfo, __u32 ErrDetail) +{ + I3C_TASK_INFO_t *pTaskInfo; + I3C_DEVICE_INFO_t *pDevice; + I3C_BUS_INFO_t *pBus; + __u32 ret; + + if (TaskInfo == 0) { + return I3C_ERR_PARAMETER_INVALID; + } + + pTaskInfo = (I3C_TASK_INFO_t *)TaskInfo; + + if (ErrDetail == I3C_ERR_HW_NOT_SUPPORT) { + } else if (ErrDetail == I3C_ERR_NACK) { + /* Master nack the slave task */ + } else if (ErrDetail == I3C_ERR_NACK_SLVSTART) { + return I3C_DO_NACK_SLVSTART(pTaskInfo); + } else if (ErrDetail == I3C_ERR_OK) { + if (pTaskInfo->callback != NULL) { + } + } + + pDevice = I3C_Get_INODE(pTaskInfo->Port); + + if (pDevice->pOwner == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + + pBus = pDevice->pOwner; + + ret = pTaskInfo->result; + I3C_Complete_Task(pTaskInfo); + pBus->pCurrentTask = NULL; + pBus->busState = I3C_BUS_STATE_IDLE; + return ret; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Callback if master nack any slave request + * @param [in] TaskInfo Pointer to the running task + * @return result + */ +/*------------------------------------------------------------------------------*/ +__u32 I3C_DO_NACK_SLVSTART(I3C_TASK_INFO_t *pTaskInfo) +{ + I3C_DEVICE_INFO_t *pDevice; + I3C_BUS_INFO_t *pBus; + + if (pTaskInfo == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + + if (pTaskInfo->Port >= I3C_PORT_MAX) { + return I3C_ERR_PARAMETER_INVALID; + } + + pDevice = &gI3c_dev_node_internal[pTaskInfo->Port]; + pBus = pDevice->pOwner; + + I3C_Notify(pTaskInfo); + I3C_Complete_Task(pTaskInfo); + pBus->pCurrentTask = NULL; + pBus->busState = I3C_BUS_STATE_IDLE; + + return I3C_ERR_NACK_SLVSTART; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Start to run slave's task + * @param [in] Parm Pointer to taskinfo + * @return none + */ +/*------------------------------------------------------------------------------*/ +void I3C_Slave_Start_Request(__u32 Parm) +{ + I3C_TASK_INFO_t *pTaskInfo; + I3C_TRANSFER_TASK_t *pTask; + + if (Parm == 0) { + return; + } + + pTaskInfo = (I3C_TASK_INFO_t *)Parm; + + if (pTaskInfo->pTask == NULL) { + return; + } + + pTask = pTaskInfo->pTask; + + if (pTask->protocol == I3C_TRANSFER_PROTOCOL_IBI) { + hal_I3C_Start_IBI(pTaskInfo); + } else if (pTask->protocol == I3C_TRANSFER_PROTOCOL_MASTER_REQUEST) { + hal_I3C_Start_Master_Request(pTaskInfo); + } else if (pTask->protocol == I3C_TRANSFER_PROTOCOL_HOT_JOIN) { + hal_I3C_Start_HotJoin(pTaskInfo); + } +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Finish slave task + * @param [in] Parm Pointer to task + * @return none + */ +/*------------------------------------------------------------------------------*/ +void I3C_Slave_End_Request(__u32 Parm) +{ + I3C_TRANSFER_TASK_t *pTask; + I3C_TASK_INFO_t *pTaskInfo; + + if (Parm == 0) { + return; + } + + pTask = (I3C_TRANSFER_TASK_t *)Parm; + pTaskInfo = pTask->pTaskInfo; + I3C_Slave_Callback((__u32)pTaskInfo, pTaskInfo->result); +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief Assigned data to response + * @param [in] pDevice Pointer to the slave device + * @param [in] wrLen response data length + * @param [in] pWrBuf response data buffer + * @return none + */ +/*------------------------------------------------------------------------------*/ +I3C_ErrCode_Enum I3C_Slave_Prepare_Response(I3C_DEVICE_INFO_t *pDevice, __u16 wrLen, __u8 *pWrBuf) +{ + I3C_ErrCode_Enum result; + __u8 *pTxBuf; + + if (pDevice == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + if ((pWrBuf == NULL) && (wrLen != 0)) { + return I3C_ERR_PARAMETER_INVALID; + } + + if (IS_Internal_DEVICE(pDevice) == FALSE) { + return I3C_ERR_PARAMETER_INVALID; + } + + result = hal_I3C_Slave_TX_Free(pDevice->port); + if (result != I3C_ERR_OK) { + hal_I3C_Stop_Slave_TX(pDevice); + } + + pTxBuf = (__u8 *)hal_I3C_MemAlloc(wrLen); + if (pTxBuf == NULL) { + return I3C_ERR_OUT_OF_MEMORY; + } + + memcpy(pTxBuf, pWrBuf, wrLen); + pDevice->pTxBuf = pTxBuf; + pDevice->txOffset = 0; + pDevice->txLen = wrLen; + + return Setup_Slave_Write_DMA(pDevice); +} + +I3C_ErrCode_Enum I3C_Slave_Update_Pending(I3C_DEVICE_INFO_t *pDevice, __u8 mask) +{ + if (pDevice == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + + if (IS_Internal_DEVICE(pDevice) == FALSE) { + return I3C_ERR_PARAMETER_INVALID; + } + + if ((pDevice->mode != I3C_DEVICE_MODE_SLAVE_ONLY) + && (pDevice->mode != I3C_DEVICE_MODE_SECONDARY_MASTER)) { + return I3C_ERR_PARAMETER_INVALID; + } + + return hal_I3C_Set_Pending(pDevice->port, mask); +} + +I3C_ErrCode_Enum I3C_Slave_Finish_Response(I3C_DEVICE_INFO_t *pDevice) +{ + if (pDevice == NULL) + return I3C_ERR_PARAMETER_INVALID; + + if (IS_Internal_DEVICE(pDevice) == FALSE) + return I3C_ERR_PARAMETER_INVALID; + + if (pDevice->txLen == 0) + return I3C_ERR_PARAMETER_INVALID; + + pDevice->txOffset = pDevice->txLen; + + return I3C_ERR_OK; +} + +I3C_ErrCode_Enum I3C_Slave_Check_Response_Complete(I3C_DEVICE_INFO_t *pDevice) +{ + I3C_ErrCode_Enum result; + __u16 txNotSendLen; + + if (pDevice == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + + if (IS_Internal_DEVICE(pDevice) == FALSE) { + return I3C_ERR_PARAMETER_INVALID; + } + + if (pDevice->txLen == 0) { + return I3C_ERR_PARAMETER_INVALID; + } + + result = hal_I3C_Slave_Query_TxLen(pDevice->port, &txNotSendLen); + if ((result == I3C_ERR_OK) && (txNotSendLen == 0)) { + if (pDevice->pTxBuf != NULL) { + hal_I3C_MemFree(pDevice->pTxBuf); + pDevice->pTxBuf = NULL; + pDevice->txLen = 0; + } + + return I3C_ERR_OK; + } + + return I3C_ERR_PENDING; +} + +I3C_ErrCode_Enum I3C_Slave_Check_IBIDIS(I3C_DEVICE_INFO_t *pDevice, _Bool *bRet) +{ + uint8_t eventSupportMask; + + if (pDevice == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + if (bRet == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + + if (IS_Internal_DEVICE(pDevice) == FALSE) { + return I3C_ERR_PARAMETER_INVALID; + } + + eventSupportMask = hal_I3C_get_event_support_status(pDevice->port); + if (eventSupportMask & DISEC_MASK_ENINT) { + *bRet = TRUE; + } else { + *bRet = FALSE; + } + + return I3C_ERR_OK; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief configure PDMA for slave write transfer + * @param [in] pDevice Pointer to device object + * @return none + */ +/*------------------------------------------------------------------------------*/ +I3C_ErrCode_Enum Setup_Slave_Write_DMA(I3C_DEVICE_INFO_t *pDevice) +{ + if (pDevice == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + + if (pDevice->port >= I3C_PORT_MAX) { + return I3C_ERR_TASK_INVALID; + } + + if ((pDevice->txLen - pDevice->txOffset) == 0) { + return I3C_ERR_OK; + } + + hal_I3C_DMA_Write(pDevice->port, pDevice->mode, &(pDevice->pTxBuf[pDevice->txOffset]), + pDevice->txLen - pDevice->txOffset); + pDevice->txOffset = pDevice->txLen; + + return I3C_ERR_OK; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief configure PDMA for slave read transfer + * @param [in] pDevice Pointer to device object + * @return none + */ +/*------------------------------------------------------------------------------*/ +I3C_ErrCode_Enum Setup_Slave_Read_DMA(I3C_DEVICE_INFO_t *pDevice) +{ + if (pDevice == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + if (pDevice->port >= I3C_PORT_MAX) { + return I3C_ERR_TASK_INVALID; + } + + if ((pDevice->rxLen - pDevice->rxOffset) == 0) { + return I3C_ERR_OK; + } + + hal_I3C_DMA_Read(pDevice->port, pDevice->mode, &(pDevice->pRxBuf[pDevice->rxOffset]), + pDevice->rxLen - pDevice->rxOffset); + return I3C_ERR_OK; +} + +/*------------------------------------------------------------------------------*/ +/** + * @brief configure PDMA for IBI (slave write) transfer + * @param [in] pDevice Pointer to device object + * @return none + */ +/*------------------------------------------------------------------------------*/ +I3C_ErrCode_Enum Setup_Slave_IBI_DMA(I3C_DEVICE_INFO_t *pDevice) +{ + I3C_TRANSFER_TASK_t *pTask; + I3C_TRANSFER_FRAME_t *pFrame; + + if (pDevice == NULL) { + return I3C_ERR_PARAMETER_INVALID; + } + if (pDevice->port >= I3C_PORT_MAX) { + return I3C_ERR_TASK_INVALID; + } + if (pDevice->pTaskListHead == NULL) { + return I3C_ERR_TASK_INVALID; + } + + pTask = pDevice->pTaskListHead; + pTask = pDevice->pTaskListHead; + + if (pTask->frame_idx >= pTask->frame_count) { + return I3C_ERR_PARAMETER_INVALID; + } + + pFrame = &pTask->pFrameList[pTask->frame_idx]; + if ((pFrame->access_len - pFrame->access_idx) == 0) { + return I3C_ERR_OK; + } + + hal_I3C_DMA_Write(pDevice->port, pDevice->mode, &pFrame->access_buf[pFrame->access_idx], + pFrame->access_len - pFrame->access_idx); + pFrame->access_idx = pFrame->access_len; + + return I3C_ERR_OK; +} + +void I3C_Update_Dynamic_Address(__u32 Parm) +{ + I3C_PORT_Enum port; + I3C_DEVICE_INFO_t *pDevice; + + port = (I3C_PORT_Enum)Parm; + pDevice = api_I3C_Get_INODE(port); + pDevice->dynamicAddr = hal_i3c_get_dynamic_address(port); + pDevice->bRunI3C = TRUE; +} + +void I3C_Prepare_To_Read_Command(__u32 Parm) +{ + if (Parm >= I3C_PORT_MAX) + return; + + I3C_PORT_Enum port = (I3C_PORT_Enum) Parm; + I3C_DEVICE_INFO_t *pDevice = api_I3C_Get_INODE(port); + + slvRxOffset[port] = 0; + slvRxLen[port] = MAX_READ_LEN; + hal_I3C_DMA_Read(port, pDevice->mode, slvRxBuf[port], slvRxLen[port]); +} + +uint8_t GetCmdWidth(uint8_t width_type) +{ + if (width_type == 0) + return 1; + if (width_type == 1) + return 2; + return 0; +} diff --git a/drivers/i3c/i3c_common.c b/drivers/i3c/i3c_common.c new file mode 100644 index 00000000000000..d24a67bca44244 --- /dev/null +++ b/drivers/i3c/i3c_common.c @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2021 ASPEED Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +static int i3c_master_send_enec_disec(const struct device *master, uint8_t addr, bool enable, + uint8_t evt) +{ + struct i3c_ccc_cmd ccc; + uint8_t event = evt; + + ccc.addr = addr; + ccc.id = (enable == true) ? I3C_CCC_ENEC : I3C_CCC_DISEC; + if (addr != I3C_BROADCAST_ADDR) { + ccc.id |= I3C_CCC_DIRECT; + } + ccc.payload.length = 1; + ccc.payload.data = &event; + ccc.rnw = 0; + ccc.ret = 0; + + return i3c_master_send_ccc(master, &ccc); +} + +int i3c_master_send_enec(const struct device *master, uint8_t addr, uint8_t evt) +{ + return i3c_master_send_enec_disec(master, addr, true, evt); +} + +int i3c_master_send_disec(const struct device *master, uint8_t addr, uint8_t evt) +{ + return i3c_master_send_enec_disec(master, addr, false, evt); +} + +int i3c_master_send_rstdaa(const struct device *master) +{ + struct i3c_ccc_cmd ccc; + + /* RSTDAA CCC */ + ccc.addr = I3C_BROADCAST_ADDR; + ccc.id = I3C_CCC_RSTDAA; + ccc.payload.length = 0; + ccc.payload.data = NULL; + ccc.rnw = 0; + ccc.ret = 0; + + return i3c_master_send_ccc(master, &ccc); +} + +int i3c_master_send_sethid(const struct device *master) +{ + struct i3c_ccc_cmd ccc; + uint8_t hid = 0; + + ccc.addr = I3C_BROADCAST_ADDR; + ccc.id = I3C_CCC_SETHID; + ccc.payload.length = 1; + ccc.payload.data = &hid; + ccc.rnw = 0; + ccc.ret = 0; + + return i3c_master_send_ccc(master, &ccc); +} + +int i3c_master_send_aasa(const struct device *master) +{ + struct i3c_ccc_cmd ccc; + + ccc.addr = I3C_BROADCAST_ADDR; + ccc.id = I3C_CCC_SETAASA; + ccc.payload.length = 0; + ccc.payload.data = NULL; + ccc.rnw = 0; + ccc.ret = 0; + + return i3c_master_send_ccc(master, &ccc); +} + +int i3c_master_send_setmrl(const struct device *master, uint8_t addr, uint16_t mrl, + uint8_t ibi_payload_size) +{ + struct i3c_ccc_cmd ccc; + uint8_t payload[4]; + + payload[0] = mrl >> 8; + payload[1] = mrl & 0xff; + payload[2] = ibi_payload_size; + + ccc.addr = addr; + ccc.id = I3C_CCC_SETMRL; + if (addr != I3C_BROADCAST_ADDR) { + ccc.id |= I3C_CCC_DIRECT; + } + ccc.payload.length = ibi_payload_size ? 3 : 2; + ccc.payload.data = payload; + ccc.rnw = 0; + ccc.ret = 0; + + return i3c_master_send_ccc(master, &ccc); +} + +int i3c_master_send_getpid(const struct device *master, uint8_t addr, uint64_t *pid) +{ + struct i3c_ccc_cmd ccc; + int ret; + uint8_t payload[8]; + + ccc.addr = addr; + ccc.payload.length = 6; + ccc.payload.data = payload; + + ccc.rnw = 1; + ccc.id = I3C_CCC_GETPID; + ccc.ret = 0; + + ret = i3c_master_send_ccc(master, &ccc); + if (ret) { + return ret; + } + + *pid = 0; + for (int i = 0; i < 6; i++) { + int sft = (6 - i - 1) * 8; + *pid |= (uint64_t)payload[i] << sft; + } + + return 0; +} + +int i3c_master_send_getbcr(const struct device *master, uint8_t addr, uint8_t *bcr) +{ + struct i3c_ccc_cmd ccc; + int ret; + + ccc.addr = addr; + ccc.payload.length = 1; + ccc.payload.data = bcr; + + ccc.rnw = 1; + ccc.id = I3C_CCC_GETBCR; + ccc.ret = 0; + + ret = i3c_master_send_ccc(master, &ccc); + if (ret) { + return ret; + } + + return 0; +} + +/** + * @brief data read for the JESD compliant devices + * @param slave the JESD compliant device + * @param addr the address buffer + * @param addr_size size of the address buffer in byte + * @param data buffer to store the read data + * @param data_size size of the read data in byte + * @return 0 if success + */ +int i3c_jesd403_read(struct i3c_dev_desc *slave, uint8_t *addr, int addr_size, uint8_t *data, + int data_size) +{ + struct i3c_priv_xfer xfer[2]; + + __ASSERT(slave->bus, "Unregistered device\n"); + __ASSERT(!slave->info.i2c_mode, "Not I3C device\n\n"); + + xfer[0].rnw = 0; + xfer[0].len = addr_size; + xfer[0].data.out = addr; + + xfer[1].rnw = 1; + xfer[1].len = data_size; + xfer[1].data.in = data; + + return i3c_master_priv_xfer(slave, xfer, 2); +} + +/** + * @brief data write for the JESD compliant devices + * @param slave the JESD compliant device + * @param addr the address buffer + * @param addr_size size of the address buffer in byte + * @param data buffer to store the write data + * @param data_size size of the write data in byte + * @return 0 if success + */ +int i3c_jesd403_write(struct i3c_dev_desc *slave, uint8_t *addr, int addr_size, uint8_t *data, + int data_size) +{ + struct i3c_priv_xfer xfer; + uint8_t *out; + int ret; + + __ASSERT(slave->bus, "Unregistered device\n"); + __ASSERT(!slave->info.i2c_mode, "Not I3C device\n\n"); + + out = k_malloc(addr_size + data_size); + memcpy(&out[0], addr, addr_size); + memcpy(&out[addr_size], data, data_size); + + xfer.rnw = 0; + xfer.len = addr_size + data_size; + xfer.data.out = out; + + ret = i3c_master_priv_xfer(slave, &xfer, 1); + k_free(out); + + return ret; +} + +/** + * @brief data read for the I2C devices + * @param slave the I2C device + * @param add the address to be read + * @param buf buffer to store the read data + * @param length length of the read data + * @return 0 if success + */ +int i3c_i2c_read(struct i3c_dev_desc *slave, uint8_t addr, uint8_t *buf, int length) +{ + struct i3c_priv_xfer xfer[2]; + + __ASSERT(slave->bus, "Unregistered device\n"); + __ASSERT(slave->info.i2c_mode, "Not I2C device\n\n"); + + xfer[0].rnw = 0; + xfer[0].len = 1; + xfer[0].data.out = &addr; + + xfer[1].rnw = 1; + xfer[1].len = length; + xfer[1].data.in = buf; + return i3c_master_priv_xfer(slave, xfer, 2); +} + +/** + * @brief data write for the I2C devices + * @param slave the I2C device + * @param add the address to be write + * @param buf buffer to store the write data + * @param length length of the write data + * @return 0 if success + */ +int i3c_i2c_write(struct i3c_dev_desc *slave, uint8_t addr, uint8_t *buf, int length) +{ + struct i3c_priv_xfer xfer; + uint8_t *out; + int ret; + + __ASSERT(slave->bus, "Unregistered device\n"); + __ASSERT(slave->info.i2c_mode, "Not I2C device\n\n"); + + out = k_malloc(length + 1); + out[0] = addr; + memcpy(&out[1], buf, length); + + xfer.rnw = 0; + xfer.len = length + 1; + xfer.data.out = out; + ret = i3c_master_priv_xfer(slave, &xfer, 1); + k_free(out); + + return ret; +} diff --git a/drivers/i3c/i3c_npcm4xx.c b/drivers/i3c/i3c_npcm4xx.c new file mode 100644 index 00000000000000..e5f255e01d6b26 --- /dev/null +++ b/drivers/i3c/i3c_npcm4xx.c @@ -0,0 +1,3277 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "sig_id.h" + +LOG_MODULE_REGISTER(npcm4xx_i3c, CONFIG_I3C_LOG_LEVEL); + +#define I3C_NPCM4XX_CCC_TIMEOUT K_MSEC(10) +#define I3C_NPCM4XX_XFER_TIMEOUT K_MSEC(10) +#define I3C_NPCM4XX_SIR_TIMEOUT K_MSEC(10) + +#define I3C_BUS_I2C_STD_TLOW_MIN_NS 4700 +#define I3C_BUS_I2C_STD_THIGH_MIN_NS 4000 +#define I3C_BUS_I2C_STD_TR_MAX_NS 1000 +#define I3C_BUS_I2C_STD_TF_MAX_NS 300 +#define I3C_BUS_I2C_FM_TLOW_MIN_NS 1300 +#define I3C_BUS_I2C_FM_THIGH_MIN_NS 600 +#define I3C_BUS_I2C_FM_TR_MAX_NS 300 +#define I3C_BUS_I2C_FM_TF_MAX_NS 300 +#define I3C_BUS_I2C_FMP_TLOW_MIN_NS 500 +#define I3C_BUS_I2C_FMP_THIGH_MIN_NS 260 +#define I3C_BUS_I2C_FMP_TR_MAX_NS 120 +#define I3C_BUS_I2C_FMP_TF_MAX_NS 120 + +/*==========================================================================*/ +#ifndef DEVALT10 +#define DEVALT10 0x0B +#endif + +#ifndef DEVALT0 +#define DEVALT0 0x10 +#endif + +#ifndef DEVALT5 +#define DEVALT5 0x15 +#endif + +#ifndef DEVALT7 +#define DEVALT7 0x17 +#endif + +#ifndef DEVALTA +#define DEVALTA 0x1A +#endif + +#ifndef DEVPD1 +#define DEVPD1 0x29 +#endif + +#ifndef DEVPD3 +#define DEVPD3 0x7B +#endif + +int8_t i3c_npcm4xx_hw_enable_pue(int port) +{ + return 0; +} + +int8_t i3c_npcm4xx_hw_disable_pue(int port) +{ + return 0; +} + +void I3C_Enable_Interrupt(I3C_PORT_Enum port) +{ +} + +void I3C_Disable_Interrupt(I3C_PORT_Enum port) +{ +} + +void I3C_Enable_Interface(I3C_PORT_Enum port) +{ +} + +void I3C_Disable_Interface(I3C_PORT_Enum port) +{ +} + +uint8_t PDMA_I3C_CH[I3C_PORT_MAX * 2] = { +#if (I3C_PORT_MAX == I3C3_IF) + PDMA_I3C1_TX, PDMA_I3C2_TX, PDMA_I3C1_RX, PDMA_I3C2_RX +#else + PDMA_I3C1_TX, PDMA_I3C2_TX, PDMA_I3C3_TX, PDMA_I3C4_TX, PDMA_I3C5_TX, PDMA_I3C6_TX, + PDMA_I3C1_RX, PDMA_I3C2_RX, PDMA_I3C3_RX, PDMA_I3C4_RX, PDMA_I3C5_RX, PDMA_I3C6_RX +#endif +}; + +/* declare 16 pdma descriptors to handle master/slave tx + * in scatter gather mode + * Rx always use basic mode + */ +struct SCAT { + struct dsct_reg SCAT_DSCT[16] __aligned(16); +}; + +#define SCAT_T struct SCAT + +SCAT_T I3C_SCATTER_GATHER_TABLE __aligned(256); +uint32_t PDMA_TxBuf_END[I3C_PORT_MAX] __aligned(4); + +#define I3C_DSCT I3C_SCATTER_GATHER_TABLE.SCAT_DSCT + +/* typedef struct pdma_reg PDMA_T; */ + +#define PDMA_T struct pdma_reg + +#define PDMA ((PDMA_T *)PDMA_BASE_ADDR) +/*==========================================================================*/ +#define I3C_GET_REG_MCONFIG(port) sys_read32(I3C_BASE_ADDR(port) + OFFSET_MCONFIG) +#define I3C_SET_REG_MCONFIG(port, val) sys_write32(val, I3C_BASE_ADDR(port) + OFFSET_MCONFIG) + +#define I3C_GET_REG_CONFIG(port) sys_read32(I3C_BASE_ADDR(port) + OFFSET_CONFIG) +#define I3C_SET_REG_CONFIG(port, val) sys_write32(val, I3C_BASE_ADDR(port) + OFFSET_CONFIG) + +#define I3C_GET_REG_STATUS(port) sys_read32(I3C_BASE_ADDR(port) + OFFSET_STATUS) +#define I3C_SET_REG_STATUS(port, val) sys_write32(val, I3C_BASE_ADDR(port) + OFFSET_STATUS) + +#define I3C_GET_REG_CTRL(port) sys_read32(I3C_BASE_ADDR(port) + OFFSET_CTRL) +#define I3C_SET_REG_CTRL(port, val) sys_write32(val, I3C_BASE_ADDR(port) + OFFSET_CTRL) + +#define I3C_GET_REG_INTSET(port) sys_read32(I3C_BASE_ADDR(port) + OFFSET_INTSET) +#define I3C_SET_REG_INTSET(port, val) sys_write32(val, I3C_BASE_ADDR(port) + OFFSET_INTSET) + +#define I3C_SET_REG_INTCLR(port, val) sys_write32(val, I3C_BASE_ADDR(port) + OFFSET_INTCLR) + +#define I3C_GET_REG_INTMASKED(port) sys_read32(I3C_BASE_ADDR(port) + OFFSET_INTMASKED) + +#define I3C_GET_REG_ERRWARN(port) sys_read32(I3C_BASE_ADDR(port) + OFFSET_ERRWARN) +#define I3C_SET_REG_ERRWARN(port, val) sys_write32(val, I3C_BASE_ADDR(port) + OFFSET_ERRWARN) + +#define I3C_GET_REG_DMACTRL(port) sys_read32(I3C_BASE_ADDR(port) + OFFSET_DMACTRL) +#define I3C_SET_REG_DMACTRL(port, val) sys_write32(val, I3C_BASE_ADDR(port) + OFFSET_DMACTRL) + +#define I3C_GET_REG_DATACTRL(port) sys_read32(I3C_BASE_ADDR(port) + OFFSET_DATACTRL) +#define I3C_SET_REG_DATACTRL(port, val) sys_write32(val, I3C_BASE_ADDR(port) + OFFSET_DATACTRL) + +#define I3C_SET_REG_WDATAB(port, val) sys_write32(val, I3C_BASE_ADDR(port) + OFFSET_WDATAB) +#define I3C_SET_REG_WDATABE(port, val) sys_write32(val, I3C_BASE_ADDR(port) + OFFSET_WDATABE) +#define I3C_SET_REG_WDATAH(port, val) sys_write32(val, I3C_BASE_ADDR(port) + OFFSET_WDATAH) +#define I3C_SET_REG_WDATAHE(port, val) sys_write32(val, I3C_BASE_ADDR(port) + OFFSET_WDATAHE) + +#define I3C_GET_REG_RDATAB(port) sys_read32(I3C_BASE_ADDR(port) + OFFSET_RDATAB) +#define I3C_GET_REG_RDATAH(port) sys_read32(I3C_BASE_ADDR(port) + OFFSET_RDATAH) + +#define I3C_SET_REG_WDATAB1(port, val) sys_write8(val, I3C_BASE_ADDR(port) + OFFSET_WDATAB1) + +#define I3C_GET_REG_CAPABILITIES(port) sys_read32(I3C_BASE_ADDR(port) + OFFSET_CAPABILITIES) +#define I3C_GET_REG_DYNADDR(port) sys_read32(I3C_BASE_ADDR(port) + OFFSET_DYNADDR) + +#define I3C_GET_REG_MAXLIMITS(port) sys_read32(I3C_BASE_ADDR(port) + OFFSET_MAXLIMITS) +#define I3C_SET_REG_MAXLIMITS(port, val) sys_write32(val, I3C_BASE_ADDR(port) + OFFSET_MAXLIMITS) + +#define I3C_GET_REG_PARTNO(port) sys_read32(I3C_BASE_ADDR(port) + OFFSET_PARTNO) +#define I3C_SET_REG_PARTNO(port, val) sys_write32(val, I3C_BASE_ADDR(port) + OFFSET_PARTNO) + +#define I3C_GET_REG_IDEXT(port) sys_read32(I3C_BASE_ADDR(port) + OFFSET_IDEXT) +#define I3C_SET_REG_IDEXT(port, val) sys_write32(val, I3C_BASE_ADDR(port) + OFFSET_IDEXT) + +#define I3C_GET_REG_VENDORID(port) sys_read32(I3C_BASE_ADDR(port) + OFFSET_VENDORID) +#define I3C_SET_REG_VENDORID(port, val) sys_write32(val, I3C_BASE_ADDR(port) + OFFSET_VENDORID) + +#define I3C_GET_REG_TCCLOCK(port) sys_read32(I3C_BASE_ADDR(port) + OFFSET_TCCLOCK) +#define I3C_SET_REG_TCCLOCK(port, val) sys_write32(val, I3C_BASE_ADDR(port) + OFFSET_TCCLOCK) + +#define I3C_GET_REG_MCTRL(port) sys_read32(I3C_BASE_ADDR(port) + OFFSET_MCTRL) +#define I3C_SET_REG_MCTRL(port, val) sys_write32(val, I3C_BASE_ADDR(port) + OFFSET_MCTRL) + +#define I3C_GET_REG_MSTATUS(port) sys_read32(I3C_BASE_ADDR(port) + OFFSET_MSTATUS) +#define I3C_SET_REG_MSTATUS(port, val) sys_write32(val, I3C_BASE_ADDR(port) + OFFSET_MSTATUS) + +#define I3C_GET_REG_IBIRULES(port) sys_read32(I3C_BASE_ADDR(port) + OFFSET_IBIRULES) +#define I3C_SET_REG_IBIRULES(port, val) sys_write32(val, I3C_BASE_ADDR(port) + OFFSET_IBIRULES) + +#define I3C_GET_REG_MINTSET(port) sys_read32(I3C_BASE_ADDR(port) + OFFSET_MINTSET) +#define I3C_SET_REG_MINTSET(port, val) sys_write32(val, I3C_BASE_ADDR(port) + OFFSET_MINTSET) + +#define I3C_SET_REG_MINTCLR(port, val) sys_write32(val, I3C_BASE_ADDR(port) + OFFSET_MINTCLR) + +#define I3C_GET_REG_MINTMASKED(port) sys_read32(I3C_BASE_ADDR(port) + OFFSET_MINTMASKED) + +#define I3C_GET_REG_MERRWARN(port) sys_read32(I3C_BASE_ADDR(port) + OFFSET_MERRWARN) +#define I3C_SET_REG_MERRWARN(port, val) sys_write32(val, I3C_BASE_ADDR(port) + OFFSET_MERRWARN) + +#define I3C_GET_REG_MDMACTRL(port) sys_read32(I3C_BASE_ADDR(port) + OFFSET_MDMACTRL) +#define I3C_SET_REG_MDMACTRL(port, val) sys_write32(val, I3C_BASE_ADDR(port) + OFFSET_MDMACTRL) + +#define I3C_GET_REG_MDATACTRL(port) sys_read32(I3C_BASE_ADDR(port) + OFFSET_MDATACTRL) +#define I3C_SET_REG_MDATACTRL(port, val) sys_write32(val, I3C_BASE_ADDR(port) + OFFSET_MDATACTRL) + +#define I3C_SET_REG_MWDATAB(port, val) sys_write32(val, I3C_BASE_ADDR(port) + OFFSET_MWDATAB) +#define I3C_SET_REG_MWDATABE(port, val) sys_write32(val, I3C_BASE_ADDR(port) + OFFSET_MWDATABE) +#define I3C_SET_REG_MWDATAH(port, val) sys_write32(val. I3C_BASE_ADDR(port) + OFFSET_MWDATAH) +#define I3C_SET_REG_MWDATAHE(port, val) sys_write32(val, I3C_BASE_ADDR(port) + OFFSET_MWDATAHE) + +#define I3C_GET_REG_MRDATAB(port) sys_read32(I3C_BASE_ADDR(port) + OFFSET_MRDATAB) +#define I3C_GET_REG_MRDATAH(port) sys_read32(I3C_BASE_ADDR(port) + OFFSET_MRDATAH) + +#define I3C_SET_REG_MWDATAB1(port, val) sys_write8(val, I3C_BASE_ADDR(port) + OFFSET_MWDATAB1) + +#define I3C_SET_REG_MWMSG_SDR(port, val) sys_write32(val, I3C_BASE_ADDR(port) + OFFSET_MWMSG_SDR) + +#define I3C_GET_REG_MRMSG_SDR(port) sys_read32(I3C_BASE_ADDR(port) + OFFSET_MRMSG_SDR) + +#define I3C_SET_REG_MWMSG_DDR(port, val) sys_write32(val, I3C_BASE_ADDR(port) + OFFSET_MWMSG_DDR) + +#define I3C_GET_REG_MRMSG_DDR(port) sys_read32(I3C_BASE_ADDR(port) + OFFSET_MWMSG_DDR) + +#define I3C_GET_REG_MDYNADDR(port) sys_read32(I3C_BASE_ADDR(port) + OFFSET_MDYNADDR) +#define I3C_SET_REG_MDYNADDR(port, val) sys_write32(val, I3C_BASE_ADDR(port) + OFFSET_MDYNADDR) + +#define I3C_GET_REG_HDRCMD(port) sys_read32(I3C_BASE_ADDR(port) + OFFSET_HDRCMD) + +#define I3C_GET_REG_IBIEXT1(port) sys_read32(I3C_BASE_ADDR(port) + OFFSET_IBIEXT1) +#define I3C_SET_REG_IBIEXT1(port, val) sys_write32(val, I3C_BASE_ADDR(port) + OFFSET_IBIEXT1) + +#define I3C_GET_REG_IBIEXT2(port) sys_read32(I3C_BASE_ADDR(port) + OFFSET_IBIEXT2) +#define I3C_SET_REG_IBIEXT2(port, val) sys_write32(val, I3C_BASE_ADDR(port) + OFFSET_IBIEXT2) + +#define I3C_GET_REG_ID(port) sys_read32(I3C_BASE_ADDR(port) + OFFSET_ID) +/*==========================================================================*/ + +/* + * Customize Register layout to support slave device only + */ +#define I3C_REGS_COUNT_PORT 1 + +#define CMDIdx_MSG 0 +#define CMD_BUF_LEN_MSG 64 + +uint8_t I3C_REGs_BUF_CMD_MSG[CMD_BUF_LEN_MSG]; + +I3C_REG_ITEM_t I3C_REGs_PORT_SLAVE[I3C_REGS_COUNT_PORT] = { { + .cmd.cmd8 = CMDIdx_MSG, .len = CMD_BUF_LEN_MSG, .buf = I3C_REGs_BUF_CMD_MSG, + .attr.width = 0, .attr.read = TRUE, .attr.write = TRUE }, +}; + +void hal_I3C_Config_Internal_Device(I3C_PORT_Enum port, I3C_DEVICE_INFO_t *pDevice) +{ + if (port >= I3C_PORT_MAX) + return; + if (pDevice == NULL) + return; +} + +/*--------------------------------------------------------------------------------------*/ +/** + * @brief Update I3C register settings for the specific internal device + * @param [in] pDevice The I3C port + * @return None + */ +/*--------------------------------------------------------------------------------------*/ +I3C_ErrCode_Enum hal_I3C_Config_Device(I3C_DEVICE_INFO_t *pDevice) +{ + I3C_PORT_Enum port = api_I3C_Get_IPORT(pDevice); + I3C_ErrCode_Enum result = I3C_ERR_OK; + uint32_t mconfig; + uint32_t sconfig; + + if (port >= I3C_PORT_MAX) + return I3C_ERR_PARAMETER_INVALID; + + result = I3C_ERR_OK; + + /* SKEW = 0, HKEEP = 3 */ + mconfig = ((I3C_GET_REG_MCONFIG(port) & 0xF1FFFF7B) | + I3C_MCONFIG_HKEEP(I3C_MCONFIG_HKEEP_EXTBOTH)); + sconfig = I3C_GET_REG_CONFIG(port) & 0xFE7F071F; + + if (pDevice->mode == I3C_DEVICE_MODE_DISABLE) { + I3C_Disable_Interrupt(port); + I3C_Enable_Interface(port); + + I3C_SET_REG_MDYNADDR(port, I3C_GET_REG_MDYNADDR(port) & 0xFE); + I3C_SET_REG_CONFIG(port, 0x00); + I3C_SET_REG_MCONFIG(port, 0x30); + return result; + } + + I3C_SET_REG_MDATACTRL(port, I3C_GET_REG_MDATACTRL(port) | I3C_MDATACTRL_FLUSHTB_MASK | + I3C_MDATACTRL_FLUSHFB_MASK); + + I3C_SET_REG_DATACTRL(port, I3C_GET_REG_DATACTRL(port) | I3C_DATACTRL_FLUSHTB_MASK | + I3C_DATACTRL_FLUSHFB_MASK); + + I3C_SET_REG_MSTATUS(port, 0xFFFFFFFFul); + I3C_SET_REG_STATUS(port, 0xFFFFFFFFul); + + if (pDevice->capability.DMA) { + I3C_SET_REG_MDMACTRL(port, I3C_MDMACTRL_DMAWIDTH(1)); + I3C_SET_REG_DMACTRL(port, I3C_DMACTRL_DMAWIDTH(1)); + + PDMA->CHCTL |= MaskBit(PDMA_OFFSET + port) + | MaskBit(PDMA_OFFSET + I3C_PORT_MAX + port); + +#if (I3C_PORT_MAX == I3C3_IF) + if (port == I3C1_IF) { + PDMA->REQSEL0_3 = (PDMA->REQSEL0_3 & 0xFF00FF00U) | (PDMA_I3C1_TX << 0) + | (PDMA_I3C1_RX << 16); + } else { + PDMA->REQSEL0_3 = (PDMA->REQSEL0_3 & 0x00FF00FFU) | (PDMA_I3C2_TX << 8) + | (PDMA_I3C2_RX << 24); + } +#elif (PDMA_OFFSET == 0) + if (port == I3C1_IF) { + PDMA->REQSEL0_3 = (PDMA->REQSEL0_3 & 0xFFFFFF00U) | (PDMA_I3C1_TX << 0); + PDMA->REQSEL4_7 = (PDMA->REQSEL4_7 & 0xFF00FFFFU) | (PDMA_I3C1_RX << 16); + } else if (port == I3C2_IF) { + PDMA->REQSEL0_3 = (PDMA->REQSEL0_3 & 0xFFFF00FFU) | (PDMA_I3C2_TX << 8); + PDMA->REQSEL4_7 = (PDMA->REQSEL4_7 & 0x00FFFFFFU) | (PDMA_I3C2_RX << 24); + } else if (port == I3C3_IF) { + PDMA->REQSEL0_3 = (PDMA->REQSEL0_3 & 0xFF00FFFFU) | (PDMA_I3C3_TX << 16); + PDMA->REQSEL8_11 = (PDMA->REQSEL8_11 & 0xFFFFFF00U) | (PDMA_I3C3_RX << 0); + } else if (port == I3C4_IF) { + PDMA->REQSEL0_3 = (PDMA->REQSEL0_3 & 0x00FFFFFFU) | (PDMA_I3C4_TX << 24); + PDMA->REQSEL8_11 = (PDMA->REQSEL8_11 & 0xFFFF00FFU) | (PDMA_I3C4_RX << 8); + } else if (port == I3C5_IF) { + PDMA->REQSEL4_7 = (PDMA->REQSEL4_7 & 0xFFFFFF00U) | (PDMA_I3C5_TX << 0); + PDMA->REQSEL8_11 = (PDMA->REQSEL8_11 & 0xFF00FFFFU) | (PDMA_I3C5_RX << 16); + } else if (port == I3C6_IF) { + PDMA->REQSEL4_7 = (PDMA->REQSEL4_7 & 0xFFFF00FFU) | (PDMA_I3C6_TX << 8); + PDMA->REQSEL8_11 = (PDMA->REQSEL8_11 & 0x00FFFFFFU) | (PDMA_I3C6_RX << 24); + } +#elif (PDMA_OFFSET == 2) + if (port == I3C1_IF) { + PDMA->REQSEL0_3 = (PDMA->REQSEL0_3 & 0xFF00FFFFU) | (PDMA_I3C1_TX << 16); + PDMA->REQSEL8_11 = (PDMA->REQSEL8_11 & 0xFFFFFF00U) | (PDMA_I3C1_RX << 0); + } else if (port == I3C2_IF) { + PDMA->REQSEL0_3 = (PDMA->REQSEL0_3 & 0x00FFFFFFU) | (PDMA_I3C2_TX << 24); + PDMA->REQSEL8_11 = (PDMA->REQSEL8_11 & 0xFFFF00FFU) | (PDMA_I3C2_RX << 8); + } else if (port == I3C3_IF) { + PDMA->REQSEL4_7 = (PDMA->REQSEL4_7 & 0xFFFFFF00U) | (PDMA_I3C3_TX << 0); + PDMA->REQSEL8_11 = (PDMA->REQSEL8_11 & 0xFF00FFFFU) | (PDMA_I3C3_RX << 16); + } else if (port == I3C4_IF) { + PDMA->REQSEL4_7 = (PDMA->REQSEL4_7 & 0xFFFF00FFU) | (PDMA_I3C4_TX << 8); + PDMA->REQSEL8_11 = (PDMA->REQSEL8_11 & 0x00FFFFFFU) | (PDMA_I3C4_RX << 24); + } else if (port == I3C5_IF) { + PDMA->REQSEL4_7 = (PDMA->REQSEL4_7 & 0xFF00FFFFU) | (PDMA_I3C5_TX << 16); + PDMA->REQSEL12_15 = (PDMA->REQSEL12_15 & 0xFFFFFF00U) | (PDMA_I3C5_RX << 0); + } else if (port == I3C6_IF) { + PDMA->REQSEL4_7 = (PDMA->REQSEL4_7 & 0x00FFFFFFU) | (PDMA_I3C6_TX << 24); + PDMA->REQSEL12_15 = (PDMA->REQSEL12_15 & 0xFFFF00FFU) | (PDMA_I3C6_RX << 8); + } +#endif + + PDMA->INTEN = 0; + PDMA->SCATBA = (uint32_t) I3C_SCATTER_GATHER_TABLE.SCAT_DSCT; + } + + I3C_SET_REG_MAXLIMITS(port, I3C_MAXLIMITS_MAXWR(I3C_PAYLOAD_SIZE_MAX) | + I3C_MAXLIMITS_MAXRD(I3C_PAYLOAD_SIZE_MAX)); + + /* Used for the Mixed bus to send the first START frame */ + mconfig &= ~I3C_MCONFIG_ODHPP_MASK; + if (pDevice->enableOpenDrainHigh) + mconfig |= I3C_MCONFIG_ODHPP_MASK; + + /* baudrate default setting + * I3C PP: 12.5 MHz, PP_High = 40ns, PP_Low = 40ns + * I3C_OD: 1MHz, OD_High = 40ns, OD_Low = 960ns + * I2C_OD: 100 KHz, OD_High = 5000ns, OD_Low = 5000ns + */ + /* mconfig &= ~(I3C_MCONFIG_I2CBAUD_MASK | I3C_MCONFIG_ODBAUD_MASK | + * I3C_MCONFIG_PPLOW_MASK | I3C_MCONFIG_PPBAUD_MASK); + * mconfig |= I3C_MCONFIG_I2CBAUD(I2CBAUD) | I3C_MCONFIG_ODBAUD(ODBAUD) | + * I3C_MCONFIG_PPLOW(PPLOW) | I3C_MCONFIG_PPBAUD(PPBAUD); + */ + + /* Whether to emit open-drain speed STOP. */ + /* if (pDevice->enableOpenDrainStop) mconfig |= I3C_MCONFIG_ODSTOP_MASK; */ + /* else mconfig &= ~I3C_MCONFIG_ODSTOP_MASK; */ + + /* disable timeout, we can't guarantee I3C task engine always process task in time. */ + mconfig = mconfig & ~I3C_MCONFIG_DISTO_MASK; + if (pDevice->disableTimeout) + mconfig |= I3C_MCONFIG_DISTO_MASK; + + /* Always handle IBI by IBIRULES to prevent slave nack */ + /* Sould enable TIMEOUT only when we try to handle SLVSTART manually */ + + /* Init IBIRULES for those slaves support IBI without mandatory data byte */ + /* I3C_SET_REG_IBIRULES(port, I3C_IBIRULES_NOBYTE_MASK); */ + + /* OFFLINE -> BCR[3], this flag only tells master the slave might not response in time */ + sconfig &= ~I3C_CONFIG_OFFLINE_MASK; + if (pDevice->capability.OFFLINE) + sconfig |= I3C_CONFIG_OFFLINE_MASK; + + /* BAMATCH */ + sconfig &= ~I3C_CONFIG_BAMATCH_MASK; + if ((pDevice->capability.IBI) || (pDevice->capability.ASYNC0)) { + sconfig |= I3C_CONFIG_BAMATCH(I3C_CLOCK_SLOW_FREQUENCY / I3C_1MHz_VAL_CONST); + + /* if support ASYNC-0, update TCCLOCK */ + I3C_SET_REG_TCCLOCK(port, I3C_TCCLOCK_FREQ(2 * (I3C_CLOCK_FREQUENCY / + I3C_1MHz_VAL_CONST)) | I3C_TCCLOCK_ACCURACY(30)); + } + + /* HDRCMD, always enable HDRCMD to detect command process too slow */ + sconfig |= I3C_CONFIG_HDRCMD_MASK; + + /* DDROK */ + sconfig &= ~I3C_CONFIG_DDROK_MASK; + if (pDevice->capability.HDR_DDR) + sconfig |= I3C_CONFIG_DDROK_MASK; + + /* master can split read message into several small pieces to meet + * slave's write length limit + * If master try to terminate "the read", it can send STOP. + * If slave doesn't support stopSplitRead, data keep in buffer until + * all of them are read out or new "Index" register is assigned + */ + if (pDevice->stopSplitRead == FALSE) { + } + + /* assign static address */ + sconfig &= ~I3C_CONFIG_SADDR_MASK; + if (pDevice->staticAddr != 0x00) + sconfig |= I3C_CONFIG_SADDR(pDevice->staticAddr); + + sconfig &= ~I3C_CONFIG_S0IGNORE_MASK; + sconfig &= ~I3C_CONFIG_MATCHSS_MASK; + sconfig &= ~I3C_CONFIG_NACK_MASK; + + /* 0: Fixed, 1: Random */ + if (pDevice->pid[0] & 0x80) { + sconfig |= I3C_CONFIG_IDRAND_MASK; + } else { + sconfig &= ~I3C_CONFIG_IDRAND_MASK; + + /* Part ID[15:0] + Instance ID[3:0] + Vendor[11:0] */ + I3C_SET_REG_PARTNO(port, pDevice->partNumber); + + pDevice->pid[2] = (uint8_t)(pDevice->partNumber >> 24); + pDevice->pid[3] = (uint8_t)(pDevice->partNumber >> 16); + pDevice->pid[4] = (uint8_t)(pDevice->partNumber >> 8); + pDevice->pid[5] = (uint8_t)(pDevice->partNumber >> 0); + } + + pDevice->pid[0] = (uint8_t)(pDevice->vendorID >> 7); + pDevice->pid[1] = (uint8_t)(pDevice->vendorID << 1); + + I3C_SET_REG_IDEXT(port, I3C_GET_REG_IDEXT(port) & + ~(I3C_IDEXT_BCR_MASK | I3C_IDEXT_DCR_MASK)); + I3C_SET_REG_IDEXT(port, I3C_GET_REG_IDEXT(port) | + (I3C_IDEXT_BCR(pDevice->bcr) | I3C_IDEXT_DCR(pDevice->dcr))); + + I3C_SET_REG_MINTCLR(port, I3C_MINTCLR_NOWMASTER_MASK | I3C_MINTCLR_ERRWARN_MASK | + I3C_MINTCLR_IBIWON_MASK | I3C_MINTCLR_TXNOTFULL_MASK | I3C_MINTCLR_RXPEND_MASK | + I3C_MINTCLR_COMPLETE_MASK | I3C_MINTCLR_MCTRLDONE_MASK | + I3C_MINTCLR_SLVSTART_MASK); + + I3C_SET_REG_MINTSET(port, I3C_MINTSET_NOWMASTER_MASK | I3C_MINTSET_ERRWARN_MASK | + I3C_MINTSET_IBIWON_MASK | I3C_MINTSET_COMPLETE_MASK | I3C_MINTSET_SLVSTART_MASK); + + I3C_SET_REG_INTCLR(port, I3C_INTCLR_EVENT_MASK | I3C_INTCLR_CHANDLED_MASK | + I3C_INTCLR_DDRMATCHED_MASK | I3C_INTCLR_ERRWARN_MASK | I3C_INTCLR_CCC_MASK | + I3C_INTCLR_DACHG_MASK | I3C_INTCLR_TXNOTFULL_MASK | I3C_INTCLR_RXPEND_MASK | + I3C_INTCLR_STOP_MASK | I3C_INTCLR_MATCHED_MASK | I3C_INTCLR_START_MASK); + + I3C_SET_REG_INTSET(port, I3C_INTSET_CHANDLED_MASK | I3C_INTSET_DDRMATCHED_MASK | + I3C_INTSET_ERRWARN_MASK | I3C_INTSET_CCC_MASK | I3C_INTSET_DACHG_MASK | + I3C_INTSET_STOP_MASK | I3C_INTSET_START_MASK); + + if (pDevice->mode == I3C_DEVICE_MODE_CURRENT_MASTER) { + I3C_SET_REG_MDYNADDR(port, (pDevice->dynamicAddr << I3C_MDYNADDR_DADDR_SHIFT) | + I3C_MDYNADDR_DAVALID_MASK); + I3C_SET_REG_CONFIG(port, sconfig | + I3C_CONFIG_SLVENA(I3C_CONFIG_SLVENA_SLAVE_OFF)); + I3C_SET_REG_MCONFIG(port, mconfig | + I3C_MCONFIG_MSTENA(I3C_MCONFIG_MSTENA_MASTER_ON)); + } else if (pDevice->mode == I3C_DEVICE_MODE_SLAVE_ONLY) { + I3C_SET_REG_MCONFIG(port, mconfig | + I3C_MCONFIG_MSTENA(I3C_MCONFIG_MSTENA_MASTER_OFF)); + I3C_SET_REG_CONFIG(port, sconfig | + I3C_CONFIG_SLVENA(I3C_CONFIG_SLVENA_SLAVE_ON)); + } else if (pDevice->mode == I3C_DEVICE_MODE_SECONDARY_MASTER) { + I3C_SET_REG_MCONFIG(port, mconfig | + I3C_MCONFIG_MSTENA(I3C_MCONFIG_MSTENA_MASTER_CAPABLE)); + I3C_SET_REG_CONFIG(port, sconfig | + I3C_CONFIG_SLVENA(I3C_CONFIG_SLVENA_SLAVE_ON)); + } + + I3C_Enable_Interface(port); + I3C_Enable_Interrupt(port); + + if ((pDevice->mode == I3C_DEVICE_MODE_SLAVE_ONLY) + || (pDevice->mode == I3C_DEVICE_MODE_SECONDARY_MASTER)) { + I3C_Prepare_To_Read_Command((uint32_t) port); + } + + return result; +} + +int8_t LoadBaudrateSetting(I3C_TRANSFER_TYPE_Enum type, uint32_t baudrate, uint32_t *pPPBAUD, + uint32_t *pPPLOW, uint32_t *pODBAUD, uint32_t *pI2CBAUD) +{ + if (type == I3C_TRANSFER_TYPE_I2C) { + switch (baudrate) { + case I3C_TRANSFER_SPEED_I2C_1MHZ: + *pPPBAUD = 1; + *pPPLOW = 0; + *pODBAUD = 5; + *pI2CBAUD = 2; + break; + case I3C_TRANSFER_SPEED_I2C_400KHZ: + *pPPBAUD = 1; + *pPPLOW = 0; + *pODBAUD = 5; + *pI2CBAUD = 8; + break; + default: /* if (pFrame->baudrate == I3C_TRANSFER_SPEED_I2C_100KHZ) */ + *pPPBAUD = 1; + *pPPLOW = 0; + *pODBAUD = 15; + *pI2CBAUD = 13; + } + + return 0; + } + + switch (baudrate) { + case I3C_TRANSFER_SPEED_SDR_12p5MHZ: + /* I3C PP=12MHz, OD Freq = 4MHz, I2C FM+ (H=400ns, L=600ns) */ + *pPPBAUD = 1; + *pPPLOW = 0; + *pODBAUD = 4; + *pI2CBAUD = 3; + break; + case I3C_TRANSFER_SPEED_SDR_8MHZ: + /* I3C PP=8MHz, OD Freq = 4MHz, I2C FM+ (H=400ns, L=600ns) */ + *pPPBAUD = 1; + *pPPLOW = 2; + *pODBAUD = 4; + *pI2CBAUD = 3; + break; + case I3C_TRANSFER_SPEED_SDR_6MHZ: + /* I3C PP=6MHz, OD Freq = 4MHz, I2C FM+ (H=400ns, L=600ns) */ + *pPPBAUD = 1; + *pPPLOW = 4; + *pODBAUD = 4; + *pI2CBAUD = 3; + break; + case I3C_TRANSFER_SPEED_SDR_4MHZ: + /* I3C PP=4MHz, OD Freq = 4MHz, I2C FM+ (H=400ns, L=600ns) */ + *pPPBAUD = 1; + *pPPLOW = 8; + *pODBAUD = 4; + *pI2CBAUD = 3; + break; + case I3C_TRANSFER_SPEED_SDR_2MHZ: + /* I3C PP=2MHz, OD Freq = 4MHz, I2C FM+ (H=400ns, L=600ns) */ + *pPPBAUD = 1; + *pPPLOW = 16; + *pODBAUD = 4; + *pI2CBAUD = 3; + break; + case I3C_TRANSFER_SPEED_SDR_1MHZ: + /* I3C PP=1MHz, OD Freq = 4MHz, I2C FM+ (H=400ns, L=600ns) */ + *pPPBAUD = 5; + *pPPLOW = 12; + *pODBAUD = 0; + *pI2CBAUD = 6; + break; + default: + /* PP=4MHz, OD Freq = 1MHz for IBI */ + *pPPBAUD = 5; + *pPPLOW = 0; + *pODBAUD = 6; + *pI2CBAUD = 8; + } + + return 0; +} + +/* + * I3C PP High Width = (PPBAUD + 1) * fclk_width + * I3C PP Low Width = (PPLOW + PPBAUD + 1) * fclk_width + * + * if ODHPP = 1, I3C OD High Width = (PPBAUD + 1) * fclk_width + * I3C OD Low Width = (ODBAUD + 1) * (PPBAUD + 1) * fclk_width + * if ODHPP = 0, I3C OD High Width = (ODBAUD + 1) * (PPBAUD + 1) * fclk_width + * I3C OD Low Width = (ODBAUD + 1) * (PPBAUD + 1) * fclk_width + * + * I2C Low Period = I2C High Period = ((I2CBAUD / 2) + 1) * (ODBAUD + 1) * (PPBAUD + 1) * fclk_width + */ +void I3C_SetXferRate(I3C_TASK_INFO_t *pTaskInfo) +{ + bool bBroadcast = FALSE; + bool bSlaveFound = FALSE; + uint32_t PPBAUD; + uint32_t PPLOW; + uint32_t ODBAUD; + uint32_t I2CBAUD; + uint32_t ODHPP = 1; + I3C_DEVICE_INFO_t *pMasterDevice; + + uint32_t mconfig; + I3C_TRANSFER_TASK_t *pTask; + I3C_TRANSFER_PROTOCOL_Enum protocol; + I3C_TRANSFER_FRAME_t *pFrame; + I3C_DEVICE_INFO_SHORT_t *pSlaveDevInfo = NULL; + + if (pTaskInfo == NULL) + return; + + mconfig = I3C_GET_REG_MCONFIG(pTaskInfo->Port); + mconfig &= ~(I3C_MCONFIG_I2CBAUD_MASK | I3C_MCONFIG_ODHPP_MASK | I3C_MCONFIG_ODBAUD_MASK + | I3C_MCONFIG_PPLOW_MASK | I3C_MCONFIG_PPBAUD_MASK); + + pMasterDevice = api_I3C_Get_INODE(pTaskInfo->Port); + + pTask = pTaskInfo->pTask; + if (pTask->frame_idx != 0) + return; + + protocol = pTask->protocol; + pFrame = &(pTask->pFrameList[pTask->frame_idx]); + + bBroadcast = (pTask->address == I3C_BROADCAST_ADDR) + || (protocol == I3C_TRANSFER_PROTOCOL_CCCb) + || (protocol == I3C_TRANSFER_PROTOCOL_CCCw) + || (protocol == I3C_TRANSFER_PROTOCOL_CCCr) + || (protocol == I3C_TRANSFER_PROTOCOL_ENTDAA) + || (protocol == I3C_TRANSFER_PROTOCOL_EVENT); + + if (bBroadcast && (pFrame->type != I3C_TRANSFER_TYPE_I2C) + && ((pFrame->flag & I3C_TRANSFER_REPEAT_START) == 0)) { + ODHPP = 0; + } + + if (!bBroadcast) { + pSlaveDevInfo = pMasterDevice->pOwner->pDevList; + while (pSlaveDevInfo != NULL) { + if (pSlaveDevInfo->attr.b.runI3C) { + if (pSlaveDevInfo->dynamicAddr == pTask->address) + break; + } else { + if (pSlaveDevInfo->staticAddr == pTask->address) + break; + } + + pSlaveDevInfo = pSlaveDevInfo->pNextDev; + } + + bSlaveFound = (pSlaveDevInfo != NULL); + } + + if (bBroadcast) { + /* Can't make sure all slave device run in i3c mode ?*/ + /* PP=4MHz, OD Freq = 1MHz for I3C device before get dynamic address */ + PPBAUD = 5; + PPLOW = 0; + ODBAUD = 3; + I2CBAUD = 8; + } else if (bSlaveFound) { + if ((pSlaveDevInfo->attr.b.runI3C) == (pFrame->type != I3C_TRANSFER_TYPE_I2C)) { + LoadBaudrateSetting(pFrame->type, pFrame->baudrate, &PPBAUD, &PPLOW, + &ODBAUD, &I2CBAUD); + } + } + + mconfig |= I3C_MCONFIG_I2CBAUD(I2CBAUD) | I3C_MCONFIG_ODHPP(ODHPP) + | I3C_MCONFIG_ODBAUD(ODBAUD) | I3C_MCONFIG_PPLOW(PPLOW) + | I3C_MCONFIG_PPBAUD(PPBAUD); + I3C_SET_REG_MCONFIG(pTaskInfo->Port, mconfig); +} + +I3C_ErrCode_Enum hal_I3C_enable_interface(I3C_PORT_Enum port) +{ + if (port >= I3C_PORT_MAX) + return I3C_ERR_PARAMETER_INVALID; + + I3C_Enable_Interface(port); + return I3C_ERR_OK; +} + +I3C_ErrCode_Enum hal_I3C_disable_interface(I3C_PORT_Enum port) +{ + if (port >= I3C_PORT_MAX) + return I3C_ERR_PARAMETER_INVALID; + + I3C_Disable_Interface(port); + return I3C_ERR_OK; +} + +I3C_ErrCode_Enum hal_I3C_enable_interrupt(I3C_PORT_Enum port) +{ + if (port >= I3C_PORT_MAX) + return I3C_ERR_PARAMETER_INVALID; + + I3C_Disable_Interrupt(port); + return I3C_ERR_OK; +} + +I3C_ErrCode_Enum hal_I3C_disable_interrupt(I3C_PORT_Enum port) +{ + if (port >= I3C_PORT_MAX) + return I3C_ERR_PARAMETER_INVALID; + + I3C_Enable_Interrupt(port); + return I3C_ERR_OK; +} + +__u32 hal_I3C_get_mstatus(I3C_PORT_Enum port) +{ + return I3C_GET_REG_MSTATUS(port); +} + +void hal_I3C_set_mstatus(I3C_PORT_Enum port, __u32 val) +{ + I3C_SET_REG_MSTATUS(port, val); +} + +I3C_IBITYPE_Enum hal_I3C_get_ibiType(I3C_PORT_Enum port) +{ + uint32_t mstatus = I3C_GET_REG_MSTATUS(port); + uint8_t ibi_type = (uint8_t)( + (mstatus & I3C_MSTATUS_IBITYPE_MASK) >> I3C_MSTATUS_IBITYPE_SHIFT); + return ibi_type; +} + +__u8 hal_I3C_get_ibiAddr(I3C_PORT_Enum port) +{ + uint32_t mstatus = I3C_GET_REG_MSTATUS(port); + uint8_t ibi_addr = (uint8_t)( + (mstatus & I3C_MSTATUS_IBIADDR_MASK) >> I3C_MSTATUS_IBIADDR_SHIFT); + return ibi_addr; +} + +_Bool hal_I3C_Is_Master_Idle(I3C_PORT_Enum port) +{ + return ((I3C_GET_REG_MSTATUS(port) & I3C_MSTATUS_STATE_MASK) == I3C_MSTATUS_STATE_IDLE) ? + TRUE : FALSE; +} + +_Bool hal_I3C_Is_Slave_Idle(I3C_PORT_Enum port) +{ + if ((I3C_GET_REG_CONFIG(port) & I3C_CONFIG_SLVENA_MASK) == 0) + return FALSE; + if ((I3C_GET_REG_STATUS(port) & I3C_STATUS_STNOTSTOP_MASK) == 0) + return TRUE; + return FALSE; +} + +_Bool hal_I3C_Is_Master_DAA(I3C_PORT_Enum port) +{ + return ((I3C_GET_REG_MSTATUS(port) & I3C_MSTATUS_STATE_MASK) == I3C_MSTATUS_STATE_DAA) ? + TRUE : FALSE; +} + +_Bool hal_I3C_Is_Slave_DAA(I3C_PORT_Enum port) +{ + if ((I3C_GET_REG_CONFIG(port) & I3C_CONFIG_SLVENA_MASK) == 0) + return FALSE; + if (I3C_GET_REG_STATUS(port) & I3C_STATUS_STDAA_MASK) + return TRUE; + return FALSE; +} + +_Bool hal_I3C_Is_Master_SLVSTART(I3C_PORT_Enum port) +{ + return ((I3C_GET_REG_MSTATUS(port) & I3C_MSTATUS_STATE_MASK) == I3C_MSTATUS_STATE_SLVREQ) ? + TRUE : FALSE; +} + +_Bool hal_I3C_Is_Slave_SLVSTART(I3C_PORT_Enum port) +{ + if ((I3C_GET_REG_CONFIG(port) & I3C_CONFIG_SLVENA_MASK) == 0) + return FALSE; + if (I3C_GET_REG_STATUS(port) & I3C_STATUS_EVENT_MASK) + return TRUE; + return FALSE; +} + +_Bool hal_I3C_Is_Master_NORMAL(I3C_PORT_Enum port) +{ + return ((I3C_GET_REG_MSTATUS(port) & I3C_MSTATUS_STATE_MASK) == I3C_MSTATUS_STATE_NORMACT) ? + TRUE : FALSE; +} + +void hal_I3C_Nack_IBI(I3C_PORT_Enum port) +{ + I3C_SET_REG_MCTRL(port, I3C_MCTRL_REQUEST_IBI_MANUAL | I3C_MCTRL_IBIRESP(1)); +} + +void hal_I3C_Ack_IBI_Without_MDB(I3C_PORT_Enum port) +{ + I3C_SET_REG_MCTRL(port, I3C_MCTRL_REQUEST_IBI_MANUAL); +} + +void hal_I3C_Ack_IBI_With_MDB(I3C_PORT_Enum port) +{ + /* if Master ack IBI too late, Slave might nack */ + I3C_SET_REG_MCTRL(port, I3C_MCTRL_REQUEST_IBI_MANUAL | I3C_MCTRL_IBIRESP(2)); +} + +uint8_t Get_PDMA_Channel(I3C_PORT_Enum port, I3C_TRANSFER_DIR_Enum direction) +{ + /* invalid channel, 6694 only support 14 channels, 0 - 13 + * I3C PDMA channel, + * 0: I3C1_TX, 1: I3C2_TX, 2: I3C3_TX, 3: I3C4_TX, 4: I3C5_TX, 5: I3C6_TX, + * 6: I3C1_RX, 7: I3C2_RX, 8: I3C3_RX, 9: I3C4_RX, 10: I3C5_RX, 11: I3C6_RX, + */ + + if (port >= I3C_PORT_MAX) + return 0xFF; + + if (direction == I3C_TRANSFER_DIR_WRITE) + return port; + else + return (I3C_PORT_MAX + port); +} + +void hal_I3C_Disable_Master_TX_DMA(I3C_PORT_Enum port) +{ + __u8 pdma_ch; + + I3C_SET_REG_MDMACTRL(port, I3C_GET_REG_MDMACTRL(port) & ~I3C_MDMACTRL_DMATB_MASK); + + pdma_ch = Get_PDMA_Channel(port, I3C_TRANSFER_DIR_WRITE); + PDMA->CHCTL &= ~MaskBit(PDMA_OFFSET + pdma_ch); +} + +void hal_I3C_Disable_Master_RX_DMA(I3C_PORT_Enum port) +{ + __u8 pdma_ch; + + I3C_SET_REG_MDMACTRL(port, I3C_GET_REG_MDMACTRL(port) & ~I3C_MDMACTRL_DMAFB_MASK); + + pdma_ch = Get_PDMA_Channel(port, I3C_TRANSFER_DIR_READ); + PDMA->CHCTL &= ~MaskBit(PDMA_OFFSET + pdma_ch); +} + +void hal_I3C_Disable_Master_DMA(I3C_PORT_Enum port) +{ + I3C_SET_REG_MDMACTRL(port, I3C_GET_REG_MDMACTRL(port) & ~(I3C_MDMACTRL_DMAFB_MASK | + I3C_MDMACTRL_DMATB_MASK)); +} + +void hal_I3C_Reset_Master_TX(I3C_PORT_Enum port) +{ + I3C_SET_REG_MDATACTRL(port, I3C_GET_REG_MDATACTRL(port) | I3C_MDATACTRL_FLUSHTB_MASK); +} + +_Bool hal_I3C_TxFifoNotFull(I3C_PORT_Enum port) +{ + return (I3C_GET_REG_MSTATUS(port) & I3C_MSTATUS_TXNOTFULL_MASK) ? TRUE : FALSE; +} + +void hal_I3C_WriteByte(I3C_PORT_Enum port, __u8 val) +{ + I3C_SET_REG_MWDATABE(port, val); +} + +_Bool hal_I3C_DMA_Write(I3C_PORT_Enum port, I3C_DEVICE_MODE_Enum mode, __u8 *txBuf, __u16 txLen) +{ + __u8 pdma_ch; + + if (txLen == 0) + return TRUE; + if (port >= I3C_PORT_MAX) + return FALSE; + if ((mode != I3C_DEVICE_MODE_CURRENT_MASTER) && (mode != I3C_DEVICE_MODE_SLAVE_ONLY) && + (mode != I3C_DEVICE_MODE_SECONDARY_MASTER)) { + return FALSE; + } + + pdma_ch = Get_PDMA_Channel(port, I3C_TRANSFER_DIR_WRITE); + if (mode == I3C_DEVICE_MODE_CURRENT_MASTER) { + if (txLen == 1) { + /* case 1: Write Data Len = 1 and Tx FIFO not full */ + if (I3C_GET_REG_MSTATUS(port) & I3C_MSTATUS_TXNOTFULL_MASK) { + I3C_SET_REG_MWDATABE(port, *txBuf); + return TRUE; + } + + /* case 2: Write Data Len = 1, use Basic Mode */ + PDMA->CHCTL &= ~MaskBit(PDMA_OFFSET + pdma_ch); + I3C_SET_REG_MDMACTRL(port, + I3C_GET_REG_MDMACTRL(port) & ~I3C_MDMACTRL_DMATB_MASK); + + /* can't flush Tx FIFO data for DDR */ + /* 2-2. Start DMA */ + PDMA->CHCTL |= MaskBit(PDMA_OFFSET + pdma_ch); + PDMA->TDSTS = MaskBit(PDMA_OFFSET + pdma_ch); + + PDMA_TxBuf_END[pdma_ch] = txBuf[0]; + + PDMA->DSCT[PDMA_OFFSET + pdma_ch].CTL = (((uint32_t) 0) + << PDMA_DSCT_CTL_TXCNT_Pos) | PDMA_SAR_INC | PDMA_DAR_FIX | + PDMA_WIDTH_32 | PDMA_OP_BASIC | PDMA_REQ_SINGLE; + PDMA->DSCT[PDMA_OFFSET + pdma_ch].ENDSA = + (uint32_t)&PDMA_TxBuf_END[pdma_ch]; + PDMA->DSCT[PDMA_OFFSET + pdma_ch].ENDDA = + (uint32_t)&(((I3C_T *) I3C_BASE_ADDR(port))->MWDATABE); + } else { + /* case 3: Write Data Buffer > 1, use Scatter Gather Mode */ + PDMA->CHCTL &= ~MaskBit(PDMA_OFFSET + pdma_ch); + I3C_SET_REG_MDMACTRL(port, + I3C_GET_REG_MDMACTRL(port) & ~I3C_MDMACTRL_DMATB_MASK); + + /* can't flush Tx FIFO data for DDR */ + PDMA->CHCTL |= MaskBit(PDMA_OFFSET + pdma_ch); + PDMA->TDSTS = MaskBit(PDMA_OFFSET + pdma_ch); + + PDMA->DSCT[PDMA_OFFSET + pdma_ch].CTL = PDMA_OP_SCATTER; + PDMA->DSCT[PDMA_OFFSET + pdma_ch].NEXT = (uint32_t)&I3C_DSCT[pdma_ch * 2]; + + I3C_DSCT[pdma_ch * 2].CTL = (((uint32_t) txLen - 2) + << PDMA_DSCT_CTL_TXCNT_Pos) | PDMA_SAR_INC | PDMA_DAR_FIX | + PDMA_WIDTH_8 | PDMA_OP_SCATTER | PDMA_REQ_SINGLE; + I3C_DSCT[pdma_ch * 2].ENDSA = (uint32_t)&txBuf[0]; + + I3C_DSCT[pdma_ch * 2].ENDDA = + (uint32_t)&(((I3C_T *)I3C_BASE_ADDR(port))->MWDATAB1); + I3C_DSCT[pdma_ch * 2].NEXT = (uint32_t)&I3C_DSCT[pdma_ch * 2 + 1]; + + PDMA_TxBuf_END[pdma_ch] = txBuf[txLen - 1]; + I3C_DSCT[pdma_ch * 2 + 1].CTL = (((uint32_t)0) << PDMA_DSCT_CTL_TXCNT_Pos) | + PDMA_SAR_INC | PDMA_DAR_FIX | PDMA_WIDTH_32 | PDMA_OP_BASIC | + PDMA_REQ_SINGLE; + I3C_DSCT[pdma_ch * 2 + 1].ENDSA = (uint32_t)&PDMA_TxBuf_END[pdma_ch]; + I3C_DSCT[pdma_ch * 2 + 1].ENDDA = + (uint32_t)&(((I3C_T *) I3C_BASE_ADDR(port))->MWDATABE); + } + + I3C_SET_REG_MDMACTRL(port, I3C_GET_REG_MDMACTRL(port) | I3C_MDMACTRL_DMATB(2)); + return TRUE; + } + + /* Prepare for Master read slave's register, or Slave send IBI data */ + if (txLen == 1) { + if (I3C_GET_REG_STATUS(port) & I3C_STATUS_TXNOTFULL_MASK) { + I3C_SET_REG_WDATABE(port, *txBuf); + return TRUE; + } + + PDMA->CHCTL &= ~MaskBit(PDMA_OFFSET + pdma_ch); + I3C_SET_REG_DMACTRL(port, I3C_GET_REG_DMACTRL(port) & ~I3C_DMACTRL_DMATB_MASK); + I3C_SET_REG_DATACTRL(port, I3C_GET_REG_DATACTRL(port) | I3C_DATACTRL_FLUSHTB_MASK); + + PDMA->CHCTL |= MaskBit(PDMA_OFFSET + pdma_ch); + PDMA->TDSTS = MaskBit(PDMA_OFFSET + pdma_ch); + + PDMA_TxBuf_END[pdma_ch] = txBuf[0]; + + PDMA->DSCT[PDMA_OFFSET + pdma_ch].CTL = (((uint32_t)0) << PDMA_DSCT_CTL_TXCNT_Pos) + | PDMA_SAR_INC | PDMA_DAR_FIX | PDMA_WIDTH_32 | PDMA_OP_BASIC + | PDMA_REQ_SINGLE; + PDMA->DSCT[PDMA_OFFSET + pdma_ch].ENDSA = (uint32_t)&PDMA_TxBuf_END[pdma_ch]; + PDMA->DSCT[PDMA_OFFSET + pdma_ch].ENDDA = + (uint32_t) &(((I3C_T *)I3C_BASE_ADDR(port))->WDATABE); + } else { + PDMA->CHCTL &= ~MaskBit(PDMA_OFFSET + pdma_ch); + I3C_SET_REG_DMACTRL(port, I3C_GET_REG_DMACTRL(port) & ~I3C_DMACTRL_DMATB_MASK); + I3C_SET_REG_DATACTRL(port, I3C_GET_REG_DATACTRL(port) | I3C_DATACTRL_FLUSHTB_MASK); + + PDMA->CHCTL |= MaskBit(PDMA_OFFSET + pdma_ch); + PDMA->TDSTS = MaskBit(PDMA_OFFSET + pdma_ch); + + PDMA->DSCT[PDMA_OFFSET + pdma_ch].CTL = PDMA_OP_SCATTER; + PDMA->DSCT[PDMA_OFFSET + pdma_ch].NEXT = (uint32_t)&I3C_DSCT[pdma_ch * 2]; + + I3C_DSCT[pdma_ch * 2].CTL = (((uint32_t) txLen - 2) << PDMA_DSCT_CTL_TXCNT_Pos) | + PDMA_SAR_INC | PDMA_DAR_FIX | PDMA_WIDTH_8 | PDMA_OP_SCATTER | + PDMA_REQ_SINGLE; + I3C_DSCT[pdma_ch * 2].ENDSA = (uint32_t)&txBuf[0]; + I3C_DSCT[pdma_ch * 2].ENDDA = + (uint32_t)&(((I3C_T *)I3C_BASE_ADDR(port))->WDATAB1); + I3C_DSCT[pdma_ch * 2].NEXT = (uint32_t)&I3C_DSCT[pdma_ch * 2 + 1]; + + PDMA_TxBuf_END[pdma_ch] = txBuf[txLen - 1]; + + I3C_DSCT[pdma_ch * 2 + 1].CTL = (((uint32_t)0) << PDMA_DSCT_CTL_TXCNT_Pos) | + PDMA_SAR_INC | PDMA_DAR_FIX | PDMA_WIDTH_32 | PDMA_OP_BASIC | + PDMA_REQ_SINGLE; + I3C_DSCT[pdma_ch * 2 + 1].ENDSA = (uint32_t)&PDMA_TxBuf_END[pdma_ch]; + I3C_DSCT[pdma_ch * 2 + 1].ENDDA = + (uint32_t)&(((I3C_T *)I3C_BASE_ADDR(port))->WDATABE); + } + + I3C_SET_REG_DMACTRL(port, I3C_GET_REG_DMACTRL(port) | I3C_DMACTRL_DMATB(2)); + return TRUE; +} + +_Bool hal_I3C_DMA_Read(I3C_PORT_Enum port, I3C_DEVICE_MODE_Enum mode, __u8 *rxBuf, __u16 rxLen) +{ + __u8 pdma_ch; + + if (rxLen == 0) + return TRUE; + if (port >= I3C_PORT_MAX) + return FALSE; + if ((mode != I3C_DEVICE_MODE_CURRENT_MASTER) && (mode != I3C_DEVICE_MODE_SLAVE_ONLY) && + (mode != I3C_DEVICE_MODE_SECONDARY_MASTER)) { + return FALSE; + } + + pdma_ch = Get_PDMA_Channel(port, I3C_TRANSFER_DIR_READ); + + if (mode == I3C_DEVICE_MODE_CURRENT_MASTER) { + PDMA->CHCTL &= ~MaskBit(PDMA_OFFSET + pdma_ch); + I3C_SET_REG_MDMACTRL(port, I3C_GET_REG_MDMACTRL(port) & ~I3C_MDMACTRL_DMAFB_MASK); + I3C_SET_REG_MDATACTRL(port, I3C_GET_REG_MDATACTRL(port) | + I3C_MDATACTRL_FLUSHFB_MASK); + + PDMA->CHCTL |= MaskBit(PDMA_OFFSET + pdma_ch); + PDMA->TDSTS = MaskBit(PDMA_OFFSET + pdma_ch); + + PDMA->DSCT[PDMA_OFFSET + pdma_ch].CTL = + (((uint32_t)rxLen - 1) << PDMA_DSCT_CTL_TXCNT_Pos) | PDMA_SAR_FIX | + PDMA_DAR_INC | PDMA_WIDTH_8 | PDMA_OP_BASIC | PDMA_REQ_SINGLE; + PDMA->DSCT[PDMA_OFFSET + pdma_ch].ENDSA = + (uint32_t)&(((I3C_T *)I3C_BASE_ADDR(port))->MRDATAB); + PDMA->DSCT[PDMA_OFFSET + pdma_ch].ENDDA = (uint32_t)&rxBuf[0]; + + I3C_SET_REG_MDMACTRL(port, I3C_GET_REG_MDMACTRL(port) | I3C_MDMACTRL_DMAFB(2)); + return TRUE; + } + + PDMA->CHCTL &= ~MaskBit(PDMA_OFFSET + pdma_ch); + I3C_SET_REG_DMACTRL(port, I3C_GET_REG_DMACTRL(port) & ~I3C_DMACTRL_DMAFB_MASK); + I3C_SET_REG_DATACTRL(port, I3C_GET_REG_DATACTRL(port) | I3C_DATACTRL_FLUSHFB_MASK); + + PDMA->CHCTL |= MaskBit(PDMA_OFFSET + pdma_ch); + PDMA->TDSTS = MaskBit(PDMA_OFFSET + pdma_ch); + + PDMA->DSCT[PDMA_OFFSET + pdma_ch].CTL = + (((uint32_t)rxLen - 1) << PDMA_DSCT_CTL_TXCNT_Pos) | PDMA_SAR_FIX | PDMA_DAR_INC | + PDMA_WIDTH_8 | PDMA_OP_BASIC | PDMA_REQ_SINGLE; + PDMA->DSCT[PDMA_OFFSET + pdma_ch].ENDSA = + (uint32_t)&(((I3C_T *)I3C_BASE_ADDR(port))->RDATAB); + PDMA->DSCT[PDMA_OFFSET + pdma_ch].ENDDA = (uint32_t)&rxBuf[0]; + + I3C_SET_REG_DMACTRL(port, I3C_GET_REG_DMACTRL(port) | I3C_DMACTRL_DMAFB(2)); + return TRUE; +} + +uint8_t hal_i3c_get_dynamic_address(I3C_PORT_Enum port) +{ + uint32_t temp; + + temp = I3C_GET_REG_DYNADDR(port); + + if ((temp & 0x01) == 0) + return I3C_DYNAMIC_ADDR_DEFAULT_7BIT; + return (uint8_t)(temp >> 1); +} + +_Bool hal_i3c_get_capability_support_master(I3C_PORT_Enum port) +{ + return TRUE; +} + +_Bool hal_i3c_get_capability_support_slave(I3C_PORT_Enum port) +{ + return TRUE; +} + +uint16_t hal_i3c_get_capability_Tx_Fifo_Len(I3C_PORT_Enum port) +{ + uint8_t tx_fifo_len_setting; + + tx_fifo_len_setting = (I3C_GET_REG_CAPABILITIES(port) & I3C_CAPABILITIES_FIFOTX_MASK) >> + I3C_CAPABILITIES_FIFOTX_SHIFT; + + if (tx_fifo_len_setting == 1) + return 4; + if (tx_fifo_len_setting == 2) + return 8; + if (tx_fifo_len_setting == 3) + return 16; + return 0; +} + +uint16_t hal_i3c_get_capability_Rx_Fifo_Len(I3C_PORT_Enum port) +{ + uint8_t rx_fifo_len_setting; + + rx_fifo_len_setting = (I3C_GET_REG_CAPABILITIES(port) & I3C_CAPABILITIES_FIFORX_MASK) >> + I3C_CAPABILITIES_FIFORX_SHIFT; + + if (rx_fifo_len_setting == 1) + return 4; + if (rx_fifo_len_setting == 2) + return 8; + if (rx_fifo_len_setting == 3) + return 16; + return 0; +} + +bool hal_i3c_get_capability_support_DMA(I3C_PORT_Enum port) +{ + return (I3C_GET_REG_CAPABILITIES(port) & I3C_CAPABILITIES_DMA_MASK) >> + I3C_CAPABILITIES_DMA_SHIFT; +} + +bool hal_i3c_get_capability_support_INT(I3C_PORT_Enum port) +{ + return (I3C_GET_REG_CAPABILITIES(port) & I3C_CAPABILITIES_INT_MASK) >> + I3C_CAPABILITIES_INT_SHIFT; +} + +bool hal_i3c_get_capability_support_DDR(I3C_PORT_Enum port) +{ + return (I3C_GET_REG_CAPABILITIES(port) & I3C_CAPABILITIES_HDRSUPP_MASK) >> + I3C_CAPABILITIES_HDRSUPP_SHIFT; +} + +bool hal_i3c_get_capability_support_ASYNC0(I3C_PORT_Enum port) +{ + return (I3C_GET_REG_CAPABILITIES(port) & I3C_CAPABILITIES_TIMECTRL_MASK) >> + I3C_CAPABILITIES_TIMECTRL_SHIFT; +} + +bool hal_i3c_get_capability_support_IBI(I3C_PORT_Enum port) +{ + return (I3C_GET_REG_CAPABILITIES(port) & I3C_CAPABILITIES_IBI_SUPP_MASK) >> + I3C_CAPABILITIES_IBI_SUPP_SHIFT; +} + +bool hal_i3c_get_capability_support_Master_Request(I3C_PORT_Enum port) +{ + return (I3C_GET_REG_CAPABILITIES(port) & I3C_CAPABILITIES_MASTER_REQUEST_SUPP_MASK) >> + I3C_CAPABILITIES_MASTER_REQUEST_SUPP_SHIFT; +} + +bool hal_i3c_get_capability_support_Hot_Join(I3C_PORT_Enum port) +{ + return (I3C_GET_REG_CAPABILITIES(port) & I3C_CAPABILITIES_HOTJOIN_SUPP_MASK) >> + I3C_CAPABILITIES_HOTJOIN_SUPP_SHIFT; +} + +bool hal_i3c_get_capability_support_Offline(I3C_PORT_Enum port) +{ + return TRUE; +} + +bool hal_i3c_get_capability_support_V10(I3C_PORT_Enum port) +{ + return TRUE; +} + +bool hal_i3c_get_capability_support_V11(I3C_PORT_Enum port) +{ + return FALSE; +} + +uint8_t hal_I3C_get_event_support_status(I3C_PORT_Enum port) +{ + uint32_t status; + + status = I3C_GET_REG_STATUS(port); + return (uint8_t)(status >> 24); +} + +__u32 hal_I3C_get_status(I3C_PORT_Enum port) +{ + return I3C_GET_REG_STATUS(port); +} + +bool hal_I3C_run_ASYN0(I3C_PORT_Enum port) +{ + uint32_t status; + + status = I3C_GET_REG_STATUS(port); + if ((status & I3C_STATUS_TIMECTRL_MASK) == I3C_STATUS_TIMECTRL(0x01)) + return TRUE; + return FALSE; +} + +static void CLK_SysTickDelay(uint32_t us) +{ +} + +I3C_ErrCode_Enum hal_I3C_Process_Task(I3C_TASK_INFO_t *pTaskInfo) +{ + I3C_TRANSFER_TASK_t *pTask; + I3C_TRANSFER_PROTOCOL_Enum protocol; + I3C_TRANSFER_FRAME_t *pFrame; + I3C_DEVICE_INFO_t *pDevice; + uint32_t mctrl; + uint16_t rdterm; + I3C_BUS_INFO_t *pBus; + + if (pTaskInfo == NULL) + return I3C_ERR_PARAMETER_INVALID; + if (pTaskInfo->Port >= I3C_PORT_MAX) + return I3C_ERR_PARAMETER_INVALID; + + pTask = pTaskInfo->pTask; + + if (pTask == NULL) + return I3C_ERR_PARAMETER_INVALID; + if (pTask->frame_idx >= pTask->frame_count) + return I3C_ERR_PARAMETER_INVALID; + + protocol = pTask->protocol; + pFrame = &pTask->pFrameList[pTask->frame_idx]; + pDevice = api_I3C_Get_Current_Master_From_Port(pTaskInfo->Port); + + mctrl = I3C_MCTRL_ADDR(pFrame->address) | I3C_MCTRL_DIR(pFrame->direction) | + I3C_MCTRL_TYPE(pFrame->type) | I3C_MCTRL_IBIRESP(3); + + I3C_SET_REG_MSTATUS(pTaskInfo->Port, I3C_MSTATUS_MCTRLDONE_MASK); + I3C_SET_REG_MINTSET(pTaskInfo->Port, I3C_GET_REG_MINTSET(pTaskInfo->Port) | + I3C_MINTSET_MCTRLDONE_MASK); + + if (protocol == I3C_TRANSFER_PROTOCOL_ENTDAA) { + mctrl |= I3C_MCTRL_REQUEST(I3C_MCTRL_REQUEST_DO_ENTDAA); + if (pTask->frame_idx != 0) + I3C_SET_REG_MWDATAB1(pTaskInfo->Port, pFrame->access_buf[8]); + } else { + /* !!! Don't setup Rx DMA in MCTRLDONE, because RX fifo will ORUN */ + if (pFrame->direction == I3C_TRANSFER_DIR_READ) { + if (protocol == I3C_TRANSFER_PROTOCOL_EVENT) { + rdterm = (pFrame->access_len - pFrame->access_idx); + } else if (pFrame->type == I3C_TRANSFER_TYPE_DDR) { + rdterm = 2 + (pFrame->access_len - pFrame->access_idx) / 2; + if (rdterm <= I3C_MCTRL_RDTERM_MAX) + mctrl |= I3C_MCTRL_RDTERM(rdterm); + } else { + rdterm = pFrame->access_len - pFrame->access_idx; + if (rdterm <= I3C_MCTRL_RDTERM_MAX) + mctrl |= I3C_MCTRL_RDTERM(rdterm); + } + + if ((I3C_GET_REG_MDMACTRL(pTaskInfo->Port) & I3C_MDMACTRL_DMAFB_MASK) == 0) + api_I3C_Setup_Master_Read_DMA(pDevice); + } + + mctrl |= I3C_MCTRL_REQUEST(I3C_MCTRL_REQUEST_EMIT_START); + } + + if ((pDevice->bAbort == FALSE) || (protocol == I3C_TRANSFER_PROTOCOL_EVENT)) { + I3C_SetXferRate(pTaskInfo); + I3C_SET_REG_MCTRL(pTaskInfo->Port, mctrl); + return I3C_ERR_PENDING; + } else if (pDevice->bAbort) { + /* flush HDRCMD */ + I3C_SET_REG_MDATACTRL(pTaskInfo->Port, I3C_GET_REG_MDATACTRL(pTaskInfo->Port) | + I3C_MDATACTRL_FLUSHTB_MASK); + I3C_SET_REG_MDMACTRL(pTaskInfo->Port, I3C_GET_REG_MDMACTRL(pTaskInfo->Port) & + ~(I3C_MDMACTRL_DMAFB_MASK | I3C_MDMACTRL_DMATB_MASK)); + + pBus = pDevice->pOwner; + pBus->pCurrentTask = NULL; + pDevice->bAbort = FALSE; + return I3C_ERR_SLVSTART; + } + + return I3C_ERR_OK; +} + +I3C_ErrCode_Enum hal_I3C_Stop(I3C_PORT_Enum port) +{ + uint32_t mctrl; + uint32_t mstatus; + uint32_t mconfig; + + while ((I3C_GET_REG_MCTRL(port) & I3C_MCTRL_REQUEST_MASK) != I3C_MCTRL_REQUEST_NONE) { + } + + mctrl = I3C_GET_REG_MCTRL(port); + mstatus = I3C_GET_REG_MSTATUS(port); + + if ((mctrl & I3C_MCTRL_TYPE_MASK) == I3C_MCTRL_TYPE(I3C_TRANSFER_TYPE_I2C)) { + mconfig = I3C_GET_REG_MCONFIG(port); + mconfig |= I3C_MCONFIG_ODSTOP_MASK; + I3C_SET_REG_MCONFIG(port, mconfig); + } + + if ((mstatus & I3C_MSTATUS_STATE_MASK) == I3C_MSTATUS_STATE_DDR) + mctrl |= I3C_MCTRL_REQUEST_EXIT_DDR; + else + mctrl |= I3C_MCTRL_REQUEST_EMIT_STOP; + + I3C_SET_REG_MINTCLR(port, I3C_MINTCLR_MCTRLDONE_MASK); + I3C_SET_REG_MCTRL(port, mctrl); + return I3C_ERR_OK; +} + +I3C_ErrCode_Enum hal_I3C_Start_IBI(I3C_TASK_INFO_t *pTaskInfo) +{ + I3C_PORT_Enum port; + I3C_DEVICE_INFO_t *pDevice; + I3C_TRANSFER_TASK_t *pTask; + I3C_TRANSFER_FRAME_t *pFrame; + uint32_t ctrl; + + if (pTaskInfo == NULL) + return I3C_ERR_PARAMETER_INVALID; + + port = pTaskInfo->Port; + if (port >= I3C_PORT_MAX) + return I3C_ERR_PARAMETER_INVALID; + + pDevice = api_I3C_Get_INODE(port); + if ((pDevice->mode != I3C_DEVICE_MODE_SLAVE_ONLY) && + ((pDevice->mode != I3C_DEVICE_MODE_SECONDARY_MASTER))) + return I3C_ERR_PARAMETER_INVALID; + + pTask = pTaskInfo->pTask; + pFrame = &pTask->pFrameList[pTask->frame_idx]; + + ctrl = I3C_GET_REG_CTRL(port); + ctrl &= ~(I3C_CTRL_IBIDATA_MASK | I3C_CTRL_EXTDATA_MASK | I3C_CTRL_EVENT_MASK); + + /* BCR[2] = 1, then set Mandatory data byte */ + if (pDevice->bcr & 0x04) { + ctrl |= I3C_CTRL_IBIDATA(pFrame->access_buf[0]); + pFrame->access_idx++; + + /* Extended IBI data */ + if (((pFrame->access_len - pFrame->access_idx) == 0) || + ((pFrame->access_len - pFrame->access_idx) > 7)) { + ctrl |= I3C_CTRL_EXTDATA(0); + I3C_SET_REG_IBIEXT1(port, I3C_IBIEXT1_MAX(0)); + api_I3C_Setup_Slave_IBI_DMA(pDevice); + } else { + ctrl |= I3C_CTRL_EXTDATA(1); + + /* MAX = data len, CNT = 0 -> use TX FIFO */ + I3C_SET_REG_IBIEXT1(port, + I3C_IBIEXT1_MAX(pFrame->access_len - pFrame->access_idx)); + api_I3C_Setup_Slave_IBI_DMA(pDevice); + } + } + + ctrl |= I3C_CTRL_EVENT(1); + I3C_SET_REG_CTRL(port, ctrl); + + return I3C_ERR_OK; +} + +I3C_ErrCode_Enum hal_I3C_Start_Master_Request(I3C_TASK_INFO_t *pTaskInfo) +{ + I3C_PORT_Enum port; + I3C_DEVICE_INFO_t *pDevice; + __u8 pdma_ch; + uint32_t ctrl; + + if (pTaskInfo == NULL) + return I3C_ERR_PARAMETER_INVALID; + + port = pTaskInfo->Port; + if (port >= I3C_PORT_MAX) + return I3C_ERR_PARAMETER_INVALID; + + pDevice = api_I3C_Get_INODE(port); + if ((pDevice->mode != I3C_DEVICE_MODE_SLAVE_ONLY) && + ((pDevice->mode != I3C_DEVICE_MODE_SECONDARY_MASTER))) + return I3C_ERR_PARAMETER_INVALID; + + pdma_ch = Get_PDMA_Channel(port, I3C_TRANSFER_DIR_WRITE); + PDMA->CHCTL &= ~MaskBit(PDMA_OFFSET + pdma_ch); + I3C_SET_REG_DMACTRL(port, I3C_GET_REG_DMACTRL(port) & I3C_DMACTRL_DMATB_MASK); + I3C_SET_REG_DATACTRL(port, I3C_GET_REG_DATACTRL(port) | I3C_DATACTRL_FLUSHTB_MASK); + + pDevice->txLen = 0; + pDevice->txOffset = 0; + pDevice->rxLen = 0; + pDevice->rxOffset = 0; + + ctrl = I3C_GET_REG_CTRL(port); + ctrl |= I3C_CTRL_EVENT(2); + I3C_SET_REG_CTRL(port, ctrl); + return I3C_ERR_OK; +} + +I3C_ErrCode_Enum hal_I3C_Start_HotJoin(I3C_TASK_INFO_t *pTaskInfo) +{ + I3C_PORT_Enum port; + I3C_DEVICE_INFO_t *pDevice; + __u8 pdma_ch; + uint32_t ctrl; + + if (pTaskInfo == NULL) + return I3C_ERR_PARAMETER_INVALID; + + port = pTaskInfo->Port; + if (port >= I3C_PORT_MAX) + return I3C_ERR_PARAMETER_INVALID; + + pDevice = api_I3C_Get_INODE(port); + if ((pDevice->mode != I3C_DEVICE_MODE_SLAVE_ONLY) && + ((pDevice->mode != I3C_DEVICE_MODE_SECONDARY_MASTER))) + return I3C_ERR_PARAMETER_INVALID; + + pdma_ch = Get_PDMA_Channel(port, I3C_TRANSFER_DIR_WRITE); + PDMA->CHCTL &= ~MaskBit(PDMA_OFFSET + pdma_ch); + I3C_SET_REG_DMACTRL(port, I3C_GET_REG_DMACTRL(port) & ~I3C_DMACTRL_DMATB_MASK); + I3C_SET_REG_DATACTRL(port, I3C_GET_REG_DATACTRL(port) | I3C_DATACTRL_FLUSHTB_MASK); + + pDevice->txLen = 0; + pDevice->txOffset = 0; + pDevice->rxLen = 0; + pDevice->rxOffset = 0; + + ctrl = I3C_GET_REG_CTRL(port); + ctrl &= ~(I3C_CTRL_IBIDATA_MASK | I3C_CTRL_EXTDATA_MASK | I3C_CTRL_EVENT_MASK); + ctrl |= I3C_CTRL_EVENT(3); + + I3C_SET_REG_CONFIG(port, I3C_GET_REG_CONFIG(port) & ~I3C_CONFIG_SLVENA_MASK); + I3C_SET_REG_CTRL(port, ctrl); + I3C_SET_REG_CONFIG(port, I3C_GET_REG_CONFIG(port) | I3C_CONFIG_SLVENA_MASK); + return I3C_ERR_OK; +} + +I3C_ErrCode_Enum hal_I3C_Slave_TX_Free(I3C_PORT_Enum port) +{ + I3C_DEVICE_INFO_t *pDevice; + uint16_t txDataLen; + + if (port >= I3C_PORT_MAX) + return I3C_ERR_PARAMETER_INVALID; + + pDevice = api_I3C_Get_INODE(port); + if ((pDevice->mode != I3C_DEVICE_MODE_SLAVE_ONLY) && + ((pDevice->mode != I3C_DEVICE_MODE_SECONDARY_MASTER))) + return I3C_ERR_PARAMETER_INVALID; + + txDataLen = (I3C_GET_REG_DATACTRL(port) & I3C_DATACTRL_TXCOUNT_MASK) >> + I3C_DATACTRL_TXCOUNT_SHIFT; + return (txDataLen == 0) ? I3C_ERR_OK : I3C_ERR_PENDING; +} + +/* return the amount of tx data has not send out */ +I3C_ErrCode_Enum hal_I3C_Slave_Query_TxLen(I3C_PORT_Enum port, uint16_t *txLen) +{ + I3C_DEVICE_INFO_t *pDevice; + uint16_t txDataLen; + + if (port >= I3C_PORT_MAX) + return I3C_ERR_PARAMETER_INVALID; + if (txLen == NULL) + return I3C_ERR_PARAMETER_INVALID; + + pDevice = api_I3C_Get_INODE(port); + if ((pDevice->mode != I3C_DEVICE_MODE_SLAVE_ONLY) && + ((pDevice->mode != I3C_DEVICE_MODE_SECONDARY_MASTER))) + return I3C_ERR_PARAMETER_INVALID; + + txDataLen = (I3C_GET_REG_DATACTRL(port) & I3C_DATACTRL_TXCOUNT_MASK) >> + I3C_DATACTRL_TXCOUNT_SHIFT; + + *txLen = txDataLen; + return I3C_ERR_OK; +} + +I3C_ErrCode_Enum hal_I3C_Stop_Slave_TX(I3C_DEVICE_INFO_t *pDevice) +{ + uint32_t dmactrl = I3C_GET_REG_DMACTRL(pDevice->port); + uint32_t datactrl = I3C_GET_REG_DATACTRL(pDevice->port); + + dmactrl &= ~I3C_DMACTRL_DMATB_MASK; + I3C_SET_REG_DMACTRL(pDevice->port, dmactrl); + + PDMA->TDSTS = MaskBit(PDMA_OFFSET + pDevice->port); + PDMA->CHCTL &= ~MaskBit(PDMA_OFFSET + pDevice->port); + + datactrl |= I3C_MDATACTRL_FLUSHFB_MASK; + I3C_SET_REG_DATACTRL(pDevice->port, datactrl); + return I3C_ERR_OK; +} + +I3C_ErrCode_Enum hal_I3C_Set_Pending(I3C_PORT_Enum port, __u8 mask) +{ + uint32_t ctrl; + + if (port >= I3C_PORT_MAX) + return I3C_ERR_PARAMETER_INVALID; + + ctrl = I3C_GET_REG_CTRL(port); + ctrl &= ~I3C_CTRL_PENDINT_MASK; + ctrl |= I3C_CTRL_PENDINT(mask); + I3C_SET_REG_CTRL(port, ctrl); + return I3C_ERR_OK; +} + +void *hal_I3C_MemAlloc(__u32 Size) +{ + return k_malloc(Size); +} + +void hal_I3C_MemFree(void *pv) +{ + k_free(pv); +} + +static uint32_t tIMG = 400; +void hal_I3C_Master_Stall(I3C_BUS_INFO_t *pBus, I3C_PORT_Enum port) +{ + CLK_SysTickDelay(tIMG); +} + +I3C_ErrCode_Enum hal_I3C_bus_reset(I3C_PORT_Enum Port) +{ + if (Port >= I3C_PORT_MAX) + return I3C_ERR_PARAMETER_INVALID; + + return I3C_ERR_OK; +} + +I3C_ErrCode_Enum hal_I3C_bus_clear(I3C_PORT_Enum Port, uint8_t counter) +{ + if (Port >= I3C_PORT_MAX) + return I3C_ERR_PARAMETER_INVALID; + + return I3C_ERR_OK; +} + +/*==========================================================================*/ + +#define I3CG_REG1(x) ((x * 0x10) + 0x14) +#define SDA_OUT_SW_MODE_EN BIT(31) +#define SCL_OUT_SW_MODE_EN BIT(30) +#define SDA_IN_SW_MODE_EN BIT(29) +#define SCL_IN_SW_MODE_EN BIT(28) +#define SDA_IN_SW_MODE_VAL BIT(27) +#define SDA_OUT_SW_MODE_VAL BIT(25) +#define SDA_SW_MODE_OE BIT(24) +#define SCL_IN_SW_MODE_VAL BIT(23) +#define SCL_OUT_SW_MODE_VAL BIT(21) +#define SCL_SW_MODE_OE BIT(20) + +void i3c_npcm4xx_isolate_scl_sda(int inst_id, bool iso) +{ +} + +void i3c_npcm4xx_gen_tbits_low(struct i3c_npcm4xx_obj *obj) +{ +} + +void i3c_npcm4xx_toggle_scl_in(int inst_id) +{ +} + +void i3c_npcm4xx_gen_start_to_internal(int inst_id) +{ +} + +void i3c_npcm4xx_gen_stop_to_internal(int inst_id) +{ +} + +static int i3c_npcm4xx_init(const struct device *dev); + +static uint8_t *pec_append(const struct device *dev, uint8_t *ptr, uint8_t len) +{ + struct i3c_npcm4xx_config *config = DEV_CFG(dev); + I3C_PORT_Enum port; + uint8_t *xfer_buf; + uint8_t pec_v; + uint8_t addr_rnw; + + port = config->inst_id; + addr_rnw = (uint8_t)(I3C_GET_REG_DYNADDR(port) << 1) | 0x1; + xfer_buf = k_malloc(len + 1); + memcpy(xfer_buf, ptr, len); + + pec_v = crc8_ccitt(0, &addr_rnw, 1); + pec_v = crc8_ccitt(pec_v, xfer_buf, len); + LOG_DBG("pec = %x", pec_v); + xfer_buf[len] = pec_v; + + return xfer_buf; +} + +/** + * @brief validate slave device exist in the bus ? + * @param obj pointer to the bus controller + * @param addr target address + * @return + */ +static int i3c_npcm4xx_get_pos(struct i3c_npcm4xx_obj *obj, uint8_t addr) +{ + int pos; + int maxdevs = DEVICE_COUNT_MAX; + + for (pos = 0; pos < maxdevs; pos++) { + if (addr == obj->dev_addr_tbl[pos]) { + return pos; + } + } + + return -1; +} + +static void i3c_npcm4xx_wr_tx_fifo(struct i3c_npcm4xx_obj *obj, uint8_t *bytes, int nbytes) +{ + struct i3c_npcm4xx_config *config; + I3C_PORT_Enum port; + + config = obj->config; + port = config->inst_id; + + /* copy data to TX DMA */ +} + +static void i3c_npcm4xx_start_xfer(struct i3c_npcm4xx_obj *obj, struct i3c_npcm4xx_xfer *xfer) +{ + struct i3c_npcm4xx_config *config; + I3C_PORT_Enum port; + I3C_DEVICE_INFO_t *pDevice; + I3C_BUS_INFO_t *pBus; + I3C_TRANSFER_TASK_t *pTask; + I3C_TASK_INFO_t *pTaskInfo; + k_spinlock_key_t key; + + config = obj->config; + port = config->inst_id; + pDevice = api_I3C_Get_INODE(port); + pBus = api_I3C_Get_Bus_From_Port(port); + + while (pDevice->pTaskListHead != NULL) { + if (pBus->pCurrentTask == NULL) { + pTask = pDevice->pTaskListHead; + pBus->pCurrentTask = pTask; + + key = k_spin_lock(&obj->lock); + obj->curr_xfer = xfer; + + pTaskInfo = pTask->pTaskInfo; + if (pTaskInfo->MasterRequest) + I3C_Master_Start_Request((__u32)pTaskInfo); + else + I3C_Slave_Start_Request((__u32)pTaskInfo); + + k_spin_unlock(&obj->lock, key); + return; + } + } +} + +/** + * @brief Build i3c_dev_desc and add connection to bus controller + * @param dev + * @param slave + * @return + */ +int i3c_npcm4xx_master_attach_device(const struct device *dev, struct i3c_dev_desc *slave) +{ + struct i3c_npcm4xx_obj *obj = NULL; + struct i3c_npcm4xx_config *config = NULL; + I3C_PORT_Enum port; + + struct i3c_npcm4xx_dev_priv *priv; + int i, pos; + I3C_BUS_INFO_t *pBus = NULL; + I3C_DEVICE_INFO_t *pDevice = NULL; + I3C_DEVICE_INFO_t *pDeviceSlv = NULL; + I3C_DEVICE_INFO_SHORT_t *pDevInfo = NULL; + + /* allocate private data of the device */ + priv = (struct i3c_npcm4xx_dev_priv *)k_malloc(sizeof(struct i3c_npcm4xx_dev_priv)); + __ASSERT(priv, "failed to allocat device private data\n"); + + priv->pos = -1; + priv->ibi.enable = true; + priv->ibi.callbacks = NULL; + priv->ibi.context = slave; + priv->ibi.incomplete = NULL; + slave->priv_data = priv; + + if (slave->info.i2c_mode) { + slave->info.dynamic_addr = slave->info.static_addr; + } else if (slave->info.assigned_dynamic_addr) { + slave->info.dynamic_addr = slave->info.assigned_dynamic_addr; + } + + /* master might not exist in devicetree */ + /* but try to get bus from bus master first */ + if (dev != NULL) { + obj = DEV_DATA(dev); + config = obj->config; + port = config->inst_id; + pDevice = api_I3C_Get_INODE(port); + if (pDevice == NULL) + return -ENODEV; + pBus = pDevice->pOwner; + + /* assign dev as slave's bus controller */ + slave->bus = dev; + + /* find a free position from master's hw_dat_free_pos */ + for (i = 0; i < DEVICE_COUNT_MAX; i++) { + if (obj->hw_dat_free_pos & BIT(i)) + break; + } + + /* can't attach if no free space */ + if (i == DEVICE_COUNT_MAX) + return i; + + pos = i3c_npcm4xx_get_pos(obj, slave->info.dynamic_addr); + if (pos >= 0) { + LOG_WRN("addr %x has been registered at %d\n", + slave->info.dynamic_addr, pos); + return pos; + } + + priv->pos = i; + + obj->dev_addr_tbl[i] = slave->info.dynamic_addr; + obj->dev_descs[i] = slave; + obj->hw_dat_free_pos &= ~BIT(i); + } else { + /* slave device must be internal device, and attch */ + for (i = 0; i < I3C_PORT_MAX; i++) { + pDeviceSlv = api_I3C_Get_INODE(i); + if (pDeviceSlv->pid[0] != (uint8_t) slave->info.pid) + continue; + if (pDeviceSlv->pid[1] != (uint8_t)(slave->info.pid >> 8)) + continue; + if (pDeviceSlv->pid[2] != (uint8_t)(slave->info.pid >> 16)) + continue; + if (pDeviceSlv->pid[3] != (uint8_t)(slave->info.pid >> 24)) + continue; + if (pDeviceSlv->pid[4] != (uint8_t)(slave->info.pid >> 32)) + continue; + if (pDeviceSlv->pid[5] != (uint8_t)(slave->info.pid >> 48)) + continue; + + pDevInfo = pDeviceSlv->pDevInfo; + break; + } + + if (pDevInfo == NULL) + return -ENODEV; + pBus = pDeviceSlv->pOwner; + + /* bus owner outside the devicetree */ + slave->bus = NULL; + } + + if (pBus == NULL) + return -ENXIO; + + if (slave->bus == NULL) + return 0; + + if ((slave->info.static_addr == 0x6A) || (slave->info.static_addr == 0x6B)) { + LSM6DSO_DEVICE_INFO_t lsm6dso; + I3C_DEVICE_ATTRIB_t attr; + + lsm6dso.initMode = INITMODE_RSTDAA | INITMODE_SETDASA; + lsm6dso.state = I3C_LSM6DSO_STATE_DEFAULT; + lsm6dso.post_init_state = LSM6DSO_POST_INIT_STATE_Default; + + lsm6dso.i3c_device.mode = I3C_DEVICE_MODE_SLAVE_ONLY; + lsm6dso.i3c_device.pOwner = pBus; + lsm6dso.i3c_device.port = port; + lsm6dso.i3c_device.bRunI3C = FALSE; + lsm6dso.i3c_device.staticAddr = slave->info.static_addr; + lsm6dso.i3c_device.dynamicAddr = I3C_DYNAMIC_ADDR_DEFAULT_7BIT; + lsm6dso.i3c_device.pid[0] = 0x02; + lsm6dso.i3c_device.pid[1] = 0x08; + lsm6dso.i3c_device.pid[2] = 0x00; + lsm6dso.i3c_device.pid[3] = 0x6C; + lsm6dso.i3c_device.pid[4] = 0x10; + lsm6dso.i3c_device.pid[5] = 0x0B; + lsm6dso.i3c_device.bcr = 0x07; + lsm6dso.i3c_device.dcr = 0x44; + lsm6dso.i3c_device.ackIBI = FALSE; + lsm6dso.i3c_device.pReg = NULL; + + attr.U16 = 0; + attr.b.suppSLV = 1; + attr.b.present = 1; + attr.b.runI3C = 0; + + if (lsm6dso.initMode & INITMODE_POST_INIT) + attr.b.reqPostInit = 0; + if (lsm6dso.initMode & INITMODE_RSTDAA) + attr.b.reqRSTDAA = 1; + if (lsm6dso.initMode & INITMODE_SETDASA) + attr.b.reqSETDASA = 1; + if (lsm6dso.initMode & INITMODE_ENTDAA) + attr.b.suppENTDAA = 1; + + lsm6dso.i3c_device.pDevInfo = NewDevInfo(pBus, &lsm6dso, attr, + lsm6dso.i3c_device.staticAddr, lsm6dso.i3c_device.dynamicAddr, + lsm6dso.i3c_device.pid, lsm6dso.i3c_device.bcr, lsm6dso.i3c_device.dcr); + if (lsm6dso.i3c_device.pDevInfo == NULL) + return -ENXIO; + } + + return 0; +} + +int i3c_npcm4xx_master_detach_device(const struct device *dev, struct i3c_dev_desc *slave) +{ + struct i3c_npcm4xx_obj *obj = DEV_DATA(dev); + struct i3c_npcm4xx_dev_priv *priv = DESC_PRIV(slave); + int pos; + + pos = priv->pos; + if (pos < 0) { + return pos; + } + + obj->hw_dat_free_pos |= BIT(pos); + obj->dev_addr_tbl[pos] = 0; + + k_free(slave->priv_data); + obj->dev_descs[pos] = (struct i3c_dev_desc *) NULL; + return 0; +} + +int i3c_npcm4xx_master_request_ibi(struct i3c_dev_desc *i3cdev, struct i3c_ibi_callbacks *cb) +{ + return 0; +} + +int i3c_npcm4xx_master_enable_ibi(struct i3c_dev_desc *i3cdev) +{ + return 0; +} + +int i3c_npcm4xx_slave_register(const struct device *dev, struct i3c_slave_setup *slave_data) +{ + struct i3c_npcm4xx_obj *obj = DEV_DATA(dev); + + obj->slave_data.max_payload_len = slave_data->max_payload_len; + obj->slave_data.callbacks = slave_data->callbacks; + obj->slave_data.dev = slave_data->dev; + return 0; +} + +/* + * slave send mdb + */ +int i3c_npcm4xx_slave_put_read_data(const struct device *dev, struct i3c_slave_payload *data, + struct i3c_ibi_payload *ibi_notify) +{ + struct i3c_npcm4xx_config *config = DEV_CFG(dev); + struct i3c_npcm4xx_obj *obj = DEV_DATA(dev); + I3C_PORT_Enum port; + uint32_t intmasked; + uint32_t ctrl; + uint8_t *xfer_buf; + int ret = 0; + + __ASSERT_NO_MSG(data); + __ASSERT_NO_MSG(data->buf); + __ASSERT_NO_MSG(data->size); + + port = config->inst_id; + + if (ibi_notify) { + osEventFlagsClear(obj->ibi_event, ~osFlagsError); + intmasked = 0; + + ctrl = I3C_GET_REG_CTRL(port); + ctrl &= ~I3C_CTRL_IBIDATA_MASK; + ctrl |= I3C_CTRL_IBIDATA(ibi_notify->buf[0]); + I3C_SET_REG_CTRL(port, ctrl); + + if (config->ibi_append_pec) { + xfer_buf = pec_append(dev, ibi_notify->buf, ibi_notify->size); + i3c_npcm4xx_wr_tx_fifo(obj, xfer_buf, ibi_notify->size + 1); + k_free(xfer_buf); + } else { + i3c_npcm4xx_wr_tx_fifo(obj, ibi_notify->buf, ibi_notify->size); + } + } + + osEventFlagsClear(obj->data_event, ~osFlagsError); + if (config->priv_xfer_pec) { + xfer_buf = pec_append(dev, data->buf, data->size); + i3c_npcm4xx_wr_tx_fifo(obj, xfer_buf, data->size + 1); + k_free(xfer_buf); + } else { + i3c_npcm4xx_wr_tx_fifo(obj, data->buf, data->size); + } + + return ret; +} + +int i3c_npcm4xx_slave_send_sir(const struct device *dev, struct i3c_ibi_payload *payload) +{ + return 0; +} + +int i3c_npcm4xx_slave_get_dynamic_addr(const struct device *dev, uint8_t *dynamic_addr) +{ + struct i3c_npcm4xx_config *config = DEV_CFG(dev); + I3C_PORT_Enum port; + uint32_t addr; + + port = config->inst_id; + addr = I3C_GET_REG_DYNADDR(port); + if ((addr & I3C_DYNADDR_DAVALID_MASK) == 0) + return -1; + + *dynamic_addr = (uint8_t)(addr >> 1); + return 0; +} + +int i3c_npcm4xx_slave_get_event_enabling(const struct device *dev, uint32_t *event_en) +{ + struct i3c_npcm4xx_config *config = DEV_CFG(dev); + I3C_PORT_Enum port; + uint32_t status; + + port = config->inst_id; + status = I3C_GET_REG_STATUS(port); + + *event_en = 0; + if ((status & I3C_STATUS_IBIDIS_MASK) == 0) + *event_en |= I3C_SLAVE_EVENT_SIR; + if ((status & I3C_STATUS_MRDIS_MASK) == 0) + *event_en |= I3C_SLAVE_EVENT_MR; + if ((status & I3C_STATUS_HJDIS_MASK) == 0) + *event_en |= I3C_SLAVE_EVENT_HJ; + + return 0; +} + +union i3c_device_cmd_queue_port_s { + volatile uint32_t value; + +#define COMMAND_PORT_XFER_CMD 0x0 +#define COMMAND_PORT_XFER_ARG 0x1 +#define COMMAND_PORT_SHORT_ARG 0x2 +#define COMMAND_PORT_ADDR_ASSIGN 0x3 +#define COMMAND_PORT_SLAVE_DATA_CMD 0x0 + +#define COMMAND_PORT_SPEED_I3C_SDR 0 +#define COMMAND_PORT_SPEED_I3C_I2C_FM 7 +#define COMMAND_PORT_SPEED_I2C_FM 0 +#define COMMAND_PORT_SPEED_I2C_FMP 1 + struct { + volatile uint32_t cmd_attr :3; /* bit[2:0] */ + volatile uint32_t tid :4; /* bit[6:3] */ + volatile uint32_t cmd :8; /* bit[14:7] */ + volatile uint32_t cp :1; /* bit[15] */ + volatile uint32_t dev_idx :5; /* bit[20:16] */ + volatile uint32_t speed :3; /* bit[23:21] */ + volatile uint32_t reserved0 :2; /* bit[25:24] */ + volatile uint32_t roc :1; /* bit[26] */ + volatile uint32_t sdap :1; /* bit[27] */ + volatile uint32_t rnw :1; /* bit[28] */ + volatile uint32_t reserved1 :1; /* bit[29] */ + volatile uint32_t toc :1; /* bit[30] */ + volatile uint32_t pec :1; /* bit[31] */ + } xfer_cmd; + + struct { + volatile uint32_t cmd_attr :3; /* bit[2:0] */ + volatile uint32_t reserved0 :5; /* bit[7:3] */ + volatile uint32_t db :8; /* bit[15:8] */ + volatile uint32_t dl :16; /* bit[31:16] */ + } xfer_arg; + + struct { + volatile uint32_t cmd_attr :3; /* bit[2:0] */ + volatile uint32_t byte_strb :3; /* bit[5:3] */ + volatile uint32_t reserved0 :2; /* bit[7:6] */ + volatile uint32_t db0 :8; /* bit[15:8] */ + volatile uint32_t db1 :8; /* bit[23:16] */ + volatile uint32_t db2 :8; /* bit[31:24] */ + } short_data_arg; + + struct { + volatile uint32_t cmd_attr :3; /* bit[2:0] */ + volatile uint32_t tid :4; /* bit[6:3] */ + volatile uint32_t cmd :8; /* bit[14:7] */ + volatile uint32_t cp :1; /* bit[15] */ + volatile uint32_t dev_idx :5; /* bit[20:16] */ + volatile uint32_t dev_cnt :3; /* bit[23:21] */ + volatile uint32_t reserved0 :2; /* bit[25:24] */ + volatile uint32_t roc :1; /* bit[26] */ + volatile uint32_t reserved1 :3; /* bit[29:27] */ + volatile uint32_t toc :1; /* bit[30] */ + volatile uint32_t reserved2 :1; /* bit[31] */ + } addr_assign_cmd; + + struct { + volatile uint32_t cmd_attr :3; /* bit[2:0] */ + volatile uint32_t tid :3; /* bit[5:3] */ + volatile uint32_t reserved0 :10; /* bit[15:5] */ + volatile uint32_t dl :16; /* bit[31:16] */ + } slave_data_cmd; +}; +/* offset 0x0c */ + +int i3c_npcm4xx_master_send_ccc(const struct device *dev, struct i3c_ccc_cmd *ccc) +{ + struct i3c_npcm4xx_obj *obj = DEV_DATA(dev); + struct i3c_npcm4xx_config *config; + struct i3c_npcm4xx_xfer xfer; + struct i3c_npcm4xx_cmd cmd; + union i3c_device_cmd_queue_port_s cmd_hi, cmd_lo; + int pos = 0; + int ret; + + /* To construct task */ + __u8 CCC; + __u32 Baudrate = 0; + __u32 Timeout = TIMEOUT_TYPICAL; + ptrI3C_RetFunc callback = NULL; + __u8 PortId; + I3C_TASK_POLICY_Enum Policy = I3C_TASK_POLICY_APPEND_LAST; + bool bHIF = NOT_HIF; + + __u16 TxLen = 0; + __u8 TxBuf[I3C_PAYLOAD_SIZE_MAX] = { 0 }; + __u16 RxLen = 0; + __u8 *RxBuf = NULL; + + if (ccc->id & I3C_CCC_DIRECT) { + pos = i3c_npcm4xx_get_pos(obj, ccc->addr); + if (pos < 0) { + return pos; + } + } + + xfer.ncmds = 1; + xfer.cmds = &cmd; + xfer.ret = 0; + + cmd.ret = 0; + if (ccc->rnw) { + cmd.rx_buf = ccc->payload.data; + cmd.rx_length = ccc->payload.length; + cmd.tx_length = 0; + } else { + cmd.tx_buf = ccc->payload.data; + cmd.tx_length = ccc->payload.length; + cmd.rx_length = 0; + } + + cmd_hi.value = 0; + cmd_hi.xfer_arg.cmd_attr = COMMAND_PORT_XFER_ARG; + cmd_hi.xfer_arg.dl = ccc->payload.length; + + cmd_lo.value = 0; + cmd_lo.xfer_cmd.cmd_attr = COMMAND_PORT_XFER_CMD; + cmd_lo.xfer_cmd.cp = 1; + cmd_lo.xfer_cmd.dev_idx = pos; + cmd_lo.xfer_cmd.cmd = ccc->id; + cmd_lo.xfer_cmd.roc = 1; + cmd_lo.xfer_cmd.rnw = ccc->rnw; + cmd_lo.xfer_cmd.toc = 1; + if (ccc->id == I3C_CCC_SETHID || ccc->id == I3C_CCC_DEVCTRL) { + cmd_lo.xfer_cmd.speed = COMMAND_PORT_SPEED_I3C_I2C_FM; + } + cmd.cmd_hi = cmd_hi.value; + cmd.cmd_lo = cmd_lo.value; + + config = obj->config; + + CCC = ccc->id; + PortId = (__u8)(config->inst_id); + Baudrate = I3C_TRANSFER_SPEED_SDR_1MHZ; + Policy = I3C_TASK_POLICY_APPEND_LAST; + callback = NULL; + Timeout = TIMEOUT_TYPICAL; + bHIF = IS_HIF; + + if (ccc->id & I3C_CCC_DIRECT) { + if ((CCC == CCC_DIRECT_ENEC) || (CCC == CCC_DIRECT_DISEC)) { + if (cmd.tx_length != 1) + return -1; + if (cmd.tx_buf == NULL) + return -1; + + TxLen = 2; + TxBuf[0] = ccc->addr; + memcpy(&TxBuf[1], cmd.tx_buf, 1); + I3C_Master_Insert_Task_CCCw(CCC, 1, TxLen, TxBuf, Baudrate, Timeout, + callback, PortId, Policy, bHIF); + } else if (CCC == CCC_DIRECT_RSTDAA) { + if (cmd.tx_length != 0) + return -1; + + TxLen = 1; + TxBuf[0] = ccc->addr; + I3C_Master_Insert_Task_CCCw(CCC, 1, TxLen, TxBuf, Baudrate, Timeout, + callback, PortId, Policy, bHIF); + } else if (CCC == CCC_DIRECT_SETMWL) { + if (cmd.tx_length != 2) + return -1; + if (cmd.tx_buf == NULL) + return -1; + + TxLen = 3; + TxBuf[0] = ccc->addr; + memcpy(&TxBuf[1], cmd.tx_buf, 2); + I3C_Master_Insert_Task_CCCw(CCC, 1, TxLen, TxBuf, Baudrate, Timeout, + callback, PortId, Policy, bHIF); + } else if (CCC == CCC_DIRECT_SETMRL) { + if ((cmd.tx_length != 2) && (cmd.tx_length != 3)) + return -1; + if (cmd.tx_buf == NULL) + return -1; + + TxLen = cmd.tx_length + 1; + TxBuf[0] = ccc->addr; + memcpy(&TxBuf[1], cmd.tx_buf, cmd.tx_length); + I3C_Master_Insert_Task_CCCw(CCC, 1, TxLen, TxBuf, Baudrate, Timeout, + callback, PortId, Policy, bHIF); + } else if (CCC == CCC_DIRECT_SETDASA) { + if (cmd.tx_length != 1) + return -1; + if (cmd.tx_buf == NULL) + return -1; + + TxLen = 2; + TxBuf[0] = ccc->addr; + memcpy(&TxBuf[1], cmd.tx_buf, cmd.tx_length); + I3C_Master_Insert_Task_CCCw(CCC, 1, TxLen, TxBuf, Baudrate, Timeout, + callback, PortId, Policy, bHIF); + } else if (CCC == CCC_DIRECT_GETMWL) { + TxLen = 1; + RxLen = 2; + TxBuf[0] = ccc->addr; + RxBuf = cmd.rx_buf; + I3C_Master_Insert_Task_CCCr(CCC, 1, TxLen, RxLen, TxBuf, RxBuf, Baudrate, + Timeout, callback, PortId, Policy, bHIF); + } else if (CCC == CCC_DIRECT_GETMRL) { + TxLen = 1; + RxLen = 3; + TxBuf[0] = ccc->addr; + RxBuf = cmd.rx_buf; + I3C_Master_Insert_Task_CCCr(CCC, 1, TxLen, RxLen, TxBuf, RxBuf, Baudrate, + Timeout, callback, PortId, Policy, bHIF); + } else if (CCC == CCC_DIRECT_GETPID) { + TxLen = 1; + RxLen = 6; + TxBuf[0] = ccc->addr; + RxBuf = cmd.rx_buf; + I3C_Master_Insert_Task_CCCr(CCC, 1, TxLen, RxLen, TxBuf, RxBuf, Baudrate, + Timeout, callback, PortId, Policy, bHIF); + } else if ((CCC == CCC_DIRECT_GETBCR) || (CCC == CCC_DIRECT_GETDCR) + || (CCC == CCC_DIRECT_GETACCMST)) { + TxLen = 1; + RxLen = 1; + TxBuf[0] = ccc->addr; + RxBuf = cmd.rx_buf; + I3C_Master_Insert_Task_CCCr(CCC, 1, TxLen, RxLen, TxBuf, RxBuf, Baudrate, + Timeout, callback, PortId, Policy, bHIF); + } else if (CCC == CCC_DIRECT_GETSTATUS) { + TxLen = 1; + RxLen = 2; + TxBuf[0] = ccc->addr; + RxBuf = cmd.rx_buf; + I3C_Master_Insert_Task_CCCr(CCC, 1, TxLen, RxLen, TxBuf, RxBuf, Baudrate, + Timeout, callback, PortId, Policy, bHIF); + } else { + return -2; + } + } else { + if (CCC == CCC_BROADCAST_ENTDAA) { + RxLen = (sizeof(cmd.rx_buf) >= 63) ? 63 : (sizeof(cmd.rx_buf) % 9) * 9; + RxBuf = cmd.rx_buf; + I3C_Master_Insert_Task_ENTDAA(63, RxBuf, Baudrate, Timeout, callback, + PortId, Policy, bHIF); + } else { + if ((CCC == CCC_BROADCAST_ENEC) || (CCC == CCC_BROADCAST_DISEC)) { + if (cmd.tx_length != 1) + return -1; + if (cmd.tx_buf == NULL) + return -1; + + TxLen = cmd.tx_length; + memcpy(TxBuf, cmd.tx_buf, TxLen); + } else if ((CCC == CCC_BROADCAST_RSTDAA) || + (CCC == CCC_BROADCAST_SETAASA)) { + TxLen = 0; + } else if (CCC == CCC_BROADCAST_SETMWL) { + if (cmd.tx_length != 2) + return -1; + if (cmd.tx_buf == NULL) + return -1; + + TxLen = cmd.tx_length; + memcpy(TxBuf, cmd.tx_buf, TxLen); + } else if (CCC == CCC_BROADCAST_SETMRL) { + if ((cmd.tx_length != 1) || (cmd.tx_length != 3)) + return -1; + if (cmd.tx_buf == NULL) + return -1; + + TxLen = cmd.tx_length; + memcpy(TxBuf, cmd.tx_buf, TxLen); + } else if (CCC == CCC_BROADCAST_SETHID) { + TxLen = 1; + TxBuf[0] = 0x00; + } else if (CCC == CCC_BROADCAST_DEVCTRL) { + TxLen = 3; + + TxBuf[0] = 0xE0; + TxBuf[1] = 0x00; + TxBuf[2] = 0x00; + } else { + return -2; + } + + I3C_Master_Insert_Task_CCCb(CCC, TxLen, TxBuf, Baudrate, Timeout, callback, + PortId, Policy, bHIF); + } + } + + k_sem_init(&xfer.sem, 0, 1); + xfer.ret = -ETIMEDOUT; + + i3c_npcm4xx_start_xfer(obj, &xfer); + + /* wait done, xfer.ret will be changed in ISR */ + k_sem_take(&xfer.sem, I3C_NPCM4XX_CCC_TIMEOUT); + ret = xfer.ret; + return ret; +} + +/* i3cdev -> target device */ +/* xfers -> send out data to slave or read in data from slave */ +int i3c_npcm4xx_master_priv_xfer(struct i3c_dev_desc *i3cdev, struct i3c_priv_xfer *xfers, + int nxfers) +{ + struct i3c_npcm4xx_obj *obj = DEV_DATA(i3cdev->bus); + struct i3c_npcm4xx_dev_priv *priv = DESC_PRIV(i3cdev); + struct i3c_npcm4xx_xfer xfer; + struct i3c_npcm4xx_cmd *cmds, *cmd; + union i3c_device_cmd_queue_port_s cmd_hi, cmd_lo; + int pos; + int i, ret; + + I3C_TASK_INFO_t *pTaskInfo; + bool bWnR; + I3C_TRANSFER_PROTOCOL_Enum Protocol; + __u8 Addr; + __u16 TxLen = 0; + __u16 RxLen = 0; + __u8 *TxBuf = NULL; + __u8 *RxBuf = NULL; + __u32 Baudrate; + __u32 Timeout = TIMEOUT_TYPICAL; + ptrI3C_RetFunc callback = NULL; + __u8 PortId = obj->config->inst_id; + I3C_TASK_POLICY_Enum Policy = I3C_TASK_POLICY_APPEND_LAST; + bool bHIF = IS_HIF; + + I3C_BUS_INFO_t *pBus; + I3C_DEVICE_INFO_t *pMaster; + I3C_DEVICE_INFO_SHORT_t *pSlaveDev; + + if (!nxfers) { + return 0; + } + + pBus = api_I3C_Get_Bus_From_Port(PortId); + pMaster = pBus->pCurrentMaster; + + /* get target address from master->dev_addr_tbl[pos], + * pos get from i3cdev->priv_data->pos, init during device attach + */ + if (priv == NULL) { + return DEVICE_COUNT_MAX; + } + + pos = priv->pos; + if (pos < 0) { + return pos; + } + + Addr = obj->dev_addr_tbl[pos]; + + /* find device node */ + pSlaveDev = pBus->pDevList; + while (pSlaveDev != NULL) { + if ((pSlaveDev->dynamicAddr == Addr) && (pSlaveDev->attr.b.runI3C == TRUE)) + break; + if ((pSlaveDev->staticAddr == Addr) && (pSlaveDev->attr.b.runI3C == FALSE)) + break; + pSlaveDev = pSlaveDev->pNextDev; + } + + if (pSlaveDev == NULL) { + return DEVICE_COUNT_MAX; + } + + cmds = (struct i3c_npcm4xx_cmd *)k_calloc(sizeof(struct i3c_npcm4xx_cmd), nxfers); + __ASSERT(cmds, "failed to allocat cmd\n"); + + xfer.ncmds = nxfers; + xfer.cmds = cmds; + xfer.ret = 0; + + for (i = 0; i < nxfers; i++) { + cmd = &xfer.cmds[i]; + + cmd_hi.value = 0; + cmd_hi.xfer_arg.cmd_attr = COMMAND_PORT_XFER_ARG; + cmd_hi.xfer_arg.dl = xfers[i].len; + + cmd_lo.value = 0; + if (xfers[i].rnw) { + cmd->rx_buf = xfers[i].data.in; + cmd->rx_length = xfers[i].len; + cmd_lo.xfer_cmd.rnw = 1; + } else { + cmd->tx_buf = xfers[i].data.out; + cmd->tx_length = xfers[i].len; + } + + cmd_lo.xfer_cmd.tid = i; + cmd_lo.xfer_cmd.dev_idx = pos; + cmd_lo.xfer_cmd.roc = 1; + if (i == nxfers - 1) { + cmd_lo.xfer_cmd.toc = 1; + } + + cmd->cmd_hi = cmd_hi.value; + cmd->cmd_lo = cmd_lo.value; + } + + for (i = 0; i < nxfers; i++) { + bWnR = (((i + 1) < nxfers) && (xfers[i].rnw == 0) && (xfers[i + 1].rnw == 1)); + + Baudrate = (pSlaveDev->attr.b.runI3C) ? I3C_TRANSFER_SPEED_SDR_12p5MHZ : + I3C_TRANSFER_SPEED_I2C_100KHZ; + + if (!bWnR) { + if (xfers[i].rnw) { + Protocol = (pSlaveDev->attr.b.runI3C) ? + I3C_TRANSFER_PROTOCOL_I3C_READ : + I3C_TRANSFER_PROTOCOL_I2C_READ; + RxBuf = xfers[i].data.in; + RxLen = xfers[i].len; + } else { + Protocol = (pSlaveDev->attr.b.runI3C) ? + I3C_TRANSFER_PROTOCOL_I3C_WRITE : + I3C_TRANSFER_PROTOCOL_I2C_WRITE; + TxBuf = xfers[i].data.out; + TxLen = xfers[i].len; + } + } else { + Protocol = (pSlaveDev->attr.b.runI3C) ? + I3C_TRANSFER_PROTOCOL_I3C_WRITEnREAD : + I3C_TRANSFER_PROTOCOL_I2C_WRITEnREAD; + TxBuf = xfers[i].data.out; + TxLen = xfers[i].len; + RxBuf = xfers[i + 1].data.in; + RxLen = xfers[i + 1].len; + } + + pTaskInfo = I3C_Master_Create_Task(Protocol, Addr, 0, &TxLen, &RxLen, TxBuf, RxBuf, + Baudrate, Timeout, callback, PortId, Policy, bHIF); + if (pTaskInfo != NULL) { + k_sem_init(&xfer.sem, 0, 1); + xfer.ret = -ETIMEDOUT; + i3c_npcm4xx_start_xfer(obj, &xfer); + + /* wait done, xfer.ret will be changed in ISR */ + k_sem_take(&xfer.sem, I3C_NPCM4XX_XFER_TIMEOUT); + + /* report actual read length */ + if (bWnR) + i++; + } + } + + ret = xfer.ret; + k_free(cmds); + + return ret; +} + +int i3c_npcm4xx_master_send_entdaa(struct i3c_dev_desc *i3cdev) +{ + struct i3c_npcm4xx_config *config; + I3C_PORT_Enum port; + + uint16_t rxlen = 63; + uint8_t RxBuf_expected[63]; + + config = DEV_CFG(i3cdev->bus); + port = config->inst_id; + + struct i3c_npcm4xx_obj *obj = DEV_DATA(i3cdev->bus); + struct i3c_npcm4xx_dev_priv *priv = DESC_PRIV(i3cdev); + struct i3c_npcm4xx_xfer xfer; + struct i3c_npcm4xx_cmd cmd; + union i3c_device_cmd_queue_port_s cmd_hi, cmd_lo; + + cmd_hi.value = 0; + cmd_hi.xfer_arg.cmd_attr = COMMAND_PORT_XFER_ARG; + + cmd_lo.value = 0; + cmd_lo.addr_assign_cmd.cmd = I3C_CCC_ENTDAA; + cmd_lo.addr_assign_cmd.cmd_attr = COMMAND_PORT_ADDR_ASSIGN; + cmd_lo.addr_assign_cmd.toc = 1; + cmd_lo.addr_assign_cmd.roc = 1; + + cmd_lo.addr_assign_cmd.dev_cnt = 1; + cmd_lo.addr_assign_cmd.dev_idx = priv->pos; + + cmd.cmd_hi = cmd_hi.value; + cmd.cmd_lo = cmd_lo.value; + cmd.rx_length = 0; + cmd.tx_length = 0; + + api_I3C_Master_Insert_Task_ENTDAA(rxlen, RxBuf_expected, I3C_TRANSFER_SPEED_SDR_1MHZ, + TIMEOUT_TYPICAL, NULL, port, I3C_TASK_POLICY_APPEND_LAST, IS_HIF); + + k_sem_init(&xfer.sem, 0, 1); + xfer.ret = -ETIMEDOUT; + xfer.ncmds = 1; + xfer.cmds = &cmd; + i3c_npcm4xx_start_xfer(obj, &xfer); + + /* wait done, xfer.ret will be changed in ISR */ + k_sem_take(&xfer.sem, I3C_NPCM4XX_CCC_TIMEOUT); + + return 0; +} + +/* MDB[7:5] = 111b, reserved */ +volatile uint8_t MDB = 0xFF; + +void I3C_Slave_Handle_DMA(__u32 Parm); +uint32_t I3C_Slave_Register_Access(I3C_PORT_Enum port, uint16_t rx_cnt, uint8_t *pRx_buff, + bool bHDR); + +#define ENTER_MASTER_ISR() { /* GPIO_Set_Data(GPIOC, 4, GPIO_DATA_LOW); */ } +#define EXIT_MASTER_ISR() { /* GPIO_Set_Data(GPIOC, 4, GPIO_DATA_HIGH); */ } + +#define ENTER_SLAVE_ISR() { /* GPIO_Set_Data(GPIOC, 5, GPIO_DATA_LOW); */ } +#define EXIT_SLAVE_ISR() { /* GPIO_Set_Data(GPIOC, 5, GPIO_DATA_HIGH); */ } + +void I3C_Master_ISR(uint8_t I3C_IF) +{ + I3C_TASK_INFO_t *pTaskInfo; + I3C_TRANSFER_TASK_t *pTask; + I3C_TRANSFER_FRAME_t *pFrame; + + uint32_t mctrl; + uint32_t mstatus; + uint32_t mconfig; + uint32_t mintmask; + uint32_t merrwarn; + + I3C_BUS_INFO_t *pBus; + I3C_DEVICE_INFO_t *pDevice; + uint8_t ibi_type; + + ENTER_MASTER_ISR(); + + pDevice = api_I3C_Get_Current_Master_From_Port(I3C_IF); + pBus = api_I3C_Get_Bus_From_Port(I3C_IF); + + mintmask = I3C_GET_REG_MINTMASKED(I3C_IF); + if (mintmask & I3C_MINTMASKED_ERRWARN_MASK) { + merrwarn = I3C_GET_REG_MERRWARN(I3C_IF); + I3C_SET_REG_MERRWARN(I3C_IF, merrwarn); + I3C_SET_REG_MSTATUS(I3C_IF, I3C_MSTATUS_MCTRLDONE_MASK); + + pTask = pDevice->pTaskListHead; + switch (merrwarn) { + case I3C_MERRWARN_NACK_MASK: + mstatus = I3C_GET_REG_MSTATUS(I3C_IF); + if ((mstatus & I3C_MSTATUS_STATE_MASK) == I3C_MSTATUS_STATE_DAA) { + pTask->pTaskInfo->result = I3C_ERR_NACK; + } else { + mstatus = I3C_GET_REG_MSTATUS(I3C_IF); + I3C_SET_REG_MSTATUS(I3C_IF, mstatus | I3C_MSTATUS_COMPLETE_MASK); + + if (mstatus & I3C_MSTATUS_SLVSTART_MASK) { + I3C_SET_REG_MSTATUS(I3C_IF, I3C_MSTATUS_SLVSTART_MASK); + + I3C_SET_REG_MDMACTRL(I3C_IF, I3C_GET_REG_MDMACTRL(I3C_IF) & + ~I3C_MDMACTRL_DMATB_MASK); + I3C_SET_REG_MDATACTRL(I3C_IF, + I3C_GET_REG_MDATACTRL(I3C_IF) | + I3C_MDATACTRL_FLUSHTB_MASK); + + pTask->pTaskInfo->result = I3C_ERR_SLVSTART; + I3C_SET_REG_MINTSET(I3C_IF, I3C_MINTSET_SLVSTART_MASK); + api_I3C_Master_Stop((uint32_t) pTask); + } else { + pTask->pTaskInfo->result = I3C_ERR_NACK; + api_I3C_Master_Stop((uint32_t) pTask); + EXIT_MASTER_ISR(); + return; + } + } + break; + + case I3C_MERRWARN_WRABT_MASK: + pTaskInfo = pTask->pTaskInfo; + pTaskInfo->result = I3C_ERR_WRABT; + + I3C_SET_REG_MDMACTRL(I3C_IF, + I3C_GET_REG_MDMACTRL(I3C_IF) & ~I3C_MDMACTRL_DMATB_MASK); + I3C_SET_REG_MDATACTRL(I3C_IF, + I3C_GET_REG_MDATACTRL(I3C_IF) | I3C_MDATACTRL_FLUSHTB_MASK); + api_I3C_Master_Stop((uint32_t) pDevice->pTaskListHead); + break; + + default: + LOG_INF("MErr:%X\r\n", merrwarn); + } + } + + if (mintmask & I3C_MINTMASKED_IBIWON_MASK) { + pTask = pBus->pCurrentTask; + pTaskInfo = pTask->pTaskInfo; + + /* IBIWON will enter ISR again afetr IBIAckNack */ + mstatus = I3C_GET_REG_MSTATUS(I3C_IF); + ibi_type = ((mstatus & I3C_MSTATUS_IBITYPE_MASK) >> I3C_MSTATUS_IBITYPE_SHIFT); + + if ((mstatus & I3C_MSTATUS_STATE_MASK) == I3C_MSTATUS_STATE_IBIACK) { + I3C_SET_REG_MSTATUS(I3C_IF, I3C_MSTATUS_IBIWON_MASK | + I3C_MSTATUS_COMPLETE_MASK | I3C_MSTATUS_MCTRLDONE_MASK); + + if (pDevice->ackIBI == FALSE) { + api_I3C_Master_Insert_DISEC_After_IbiNack((uint32_t) pTask); + EXIT_MASTER_ISR(); + return; + } + + /* To prevent ERRWARN.SPAR, we must ack/nak IBI ASAP */ + if (ibi_type == I3C_MSTATUS_IBITYPE_IBI) { + api_I3C_Master_IBIACK((uint32_t) pTask); + EXIT_MASTER_ISR(); + return; + } else if (ibi_type == I3C_MSTATUS_IBITYPE_MstReq) { + api_I3C_Master_Insert_GETACCMST_After_IbiAckMR((uint32_t) pTask); + EXIT_MASTER_ISR(); + return; + } else if (ibi_type == I3C_MSTATUS_IBITYPE_HotJoin) { + api_I3C_Master_Insert_ENTDAA_After_IbiAckHJ((uint32_t) pTask); + EXIT_MASTER_ISR(); + return; + } + + api_I3C_Master_Insert_DISEC_After_IbiNack((uint32_t) pTask); + EXIT_MASTER_ISR(); + return; + } + + if (ibi_type == I3C_MSTATUS_IBITYPE_IBI) { + mctrl = I3C_GET_REG_MCTRL(I3C_IF); + if ((mctrl & I3C_MCTRL_IBIRESP_MASK) == I3C_MCTRL_IBIRESP(0x01)) { + I3C_SET_REG_MSTATUS(I3C_IF, I3C_MSTATUS_IBIWON_MASK | + I3C_MSTATUS_COMPLETE_MASK | I3C_MSTATUS_MCTRLDONE_MASK); + mintmask = I3C_MINTMASKED_MCTRLDONE_MASK; + } else if (ibi_type == I3C_MSTATUS_IBITYPE_IBI) { + I3C_SET_REG_MSTATUS(I3C_IF, I3C_MSTATUS_MCTRLDONE_MASK); + pTaskInfo->result = I3C_ERR_IBI; + } + } else if (ibi_type == I3C_MSTATUS_IBITYPE_MstReq) { + } else if (ibi_type == I3C_MSTATUS_IBITYPE_HotJoin) { + } else { + /* Master nacked the SLVSTART, but can't stop immediatedly */ + } + + I3C_SET_REG_MSTATUS(I3C_IF, I3C_MSTATUS_IBIWON_MASK); + } + + if (mintmask & I3C_MINTMASKED_MCTRLDONE_MASK) { + I3C_SET_REG_MSTATUS(I3C_IF, I3C_MSTATUS_MCTRLDONE_MASK); + I3C_SET_REG_MINTCLR(I3C_IF, I3C_MINTCLR_MCTRLDONE_MASK); + + mconfig = I3C_GET_REG_MCONFIG(I3C_IF); + if ((mconfig & I3C_MCONFIG_ODHPP(1)) == 0) { + mconfig |= I3C_MCONFIG_ODHPP(1); + I3C_SET_REG_MCONFIG(I3C_IF, mconfig); + } + + mstatus = I3C_GET_REG_MSTATUS(I3C_IF); + + pTask = pDevice->pTaskListHead; + pTaskInfo = pTask->pTaskInfo; + pFrame = &pTask->pFrameList[pTask->frame_idx]; + + if ((mstatus & I3C_MSTATUS_STATE_MASK) == I3C_MSTATUS_STATE_DAA) { + if ((pTask->frame_idx + 1) >= pTask->frame_count) { + /* drop rx data, because we don't have enough memory + * to keep slave's info + */ + I3C_SET_REG_MDATACTRL(I3C_IF, + I3C_GET_REG_MDATACTRL(I3C_IF) | + I3C_MDATACTRL_FLUSHFB_MASK); + + if (mstatus & I3C_MSTATUS_BETWEEN_MASK) { + pTaskInfo->result = I3C_ERR_OK; + api_I3C_Master_Stop((uint32_t) pDevice->pTaskListHead); + } + } else { + while ((pTask->pFrameList[pTask->frame_idx + 1].access_idx < + pTask->pFrameList[pTask->frame_idx + 1].access_len)) { + pTask->pFrameList[pTask->frame_idx + 1].access_buf[ + pTask->pFrameList[pTask->frame_idx + 1].access_idx] + = I3C_GET_REG_MRDATAB(I3C_IF); + pTask->pFrameList[pTask->frame_idx + 1].access_idx++; + } + + api_I3C_Master_Run_Next_Frame((uint32_t) pTask); + } + } else if (pTask->protocol == I3C_TRANSFER_PROTOCOL_ENTDAA) { + /* no slave want to participate ENTDAA, but slave ack 7E+Wr + * HW will send STOP automatically, and we should not drive STOP + * to prevent MSGERR + */ + } else if (pFrame->direction == I3C_TRANSFER_DIR_WRITE) { + if (pFrame->access_len == 0) { + /* 7E+Wr / CCCw */ + if (pTask->frame_count == (pTask->frame_idx + 1)) { + api_I3C_Master_Stop((uint32_t) pTask); + EXIT_MASTER_ISR(); + return; + } + api_I3C_Master_Run_Next_Frame((uint32_t) pTask); + } else { + mstatus = I3C_GET_REG_MSTATUS(I3C_IF); + if (mstatus & I3C_MSTATUS_SLVSTART_MASK) { + /* Private write win the bus arbitration ==> + * address in the private write is prior than + * IBI request + * We should complete the private write task + * before handling IBI request + */ + I3C_SET_REG_MSTATUS(I3C_IF, I3C_MSTATUS_SLVSTART_MASK); + } + + if (pFrame->type == I3C_TRANSFER_TYPE_DDR) + I3C_SET_REG_MWDATAB1(I3C_IF, pFrame->hdrcmd); + api_I3C_Setup_Master_Write_DMA(pDevice); + } + } else { + if (pFrame->type == I3C_TRANSFER_TYPE_DDR) { + I3C_SET_REG_MWDATAB1(I3C_IF, pFrame->hdrcmd); + } + } + } + + if (mintmask & I3C_MINTMASKED_COMPLETE_MASK) { + I3C_SET_REG_MSTATUS(I3C_IF, I3C_MSTATUS_COMPLETE_MASK | I3C_MSTATUS_MCTRLDONE_MASK); + + pTask = pDevice->pTaskListHead; + pTaskInfo = pTask->pTaskInfo; + pFrame = &pTask->pFrameList[pTask->frame_idx]; + + /* Update the receive data length for read transfer, except ENTDAA */ + if (pFrame->direction == I3C_TRANSFER_DIR_READ) { + if (PDMA->TDSTS & MaskBit(PDMA_OFFSET + I3C_IF + I3C_PORT_MAX)) { + PDMA->TDSTS = MaskBit(PDMA_OFFSET + I3C_IF + I3C_PORT_MAX); + *pTask->pRdLen = pFrame->access_len; + } else if (I3C_GET_REG_MDMACTRL(I3C_IF) & I3C_MDMACTRL_DMAFB_MASK) { + *pTask->pRdLen = pFrame->access_len - + ((uint16_t)((PDMA->DSCT[PDMA_OFFSET + I3C_IF + + I3C_PORT_MAX].CTL & PDMA_DSCT_CTL_TXCNT_Msk) >> + PDMA_DSCT_CTL_TXCNT_Pos) + 1); + } + } + + if (PDMA->TDSTS & MaskBit(PDMA_OFFSET + I3C_IF)) { + PDMA->TDSTS = MaskBit(PDMA_OFFSET + I3C_IF); + } else if (I3C_GET_REG_MDMACTRL(I3C_IF) & I3C_MDMACTRL_DMATB_MASK) { + *pTask->pWrLen = pFrame->access_len - + ((uint16_t)((PDMA->DSCT[PDMA_OFFSET + I3C_IF].CTL & + PDMA_DSCT_CTL_TXCNT_Msk) >> + PDMA_DSCT_CTL_TXCNT_Pos) + 1); + } + + I3C_SET_REG_MDMACTRL(I3C_IF, I3C_GET_REG_MDMACTRL(I3C_IF) & + ~I3C_MDMACTRL_DMAFB_MASK); + PDMA->CHCTL &= ~MaskBit(PDMA_OFFSET + I3C_IF + I3C_PORT_MAX); + PDMA->CHCTL |= MaskBit(PDMA_OFFSET + I3C_IF + I3C_PORT_MAX); + + I3C_SET_REG_MDMACTRL(I3C_IF, I3C_GET_REG_MDMACTRL(I3C_IF) & + ~I3C_MDMACTRL_DMATB_MASK); + I3C_SET_REG_MDATACTRL(I3C_IF, I3C_GET_REG_MDATACTRL(I3C_IF) | + I3C_MDATACTRL_FLUSHTB_MASK); + PDMA->CHCTL &= ~MaskBit(PDMA_OFFSET + I3C_IF); + PDMA->CHCTL |= MaskBit(PDMA_OFFSET + I3C_IF); + + /* Error has been caught, but complete also assert */ + if (pTaskInfo->result == I3C_ERR_WRABT) { + api_I3C_Master_Stop((uint32_t) pTask); + EXIT_MASTER_ISR(); + return; + } + + if (pTaskInfo->result == I3C_ERR_IBI) { + /* slvRxOffset[I3C_IF] should less than 69 */ + slvRxOffset[I3C_IF] = *pTask->pRdLen; + memcpy(&slvRxBuf[I3C_IF][0], pTask->pRdBuf, slvRxOffset[I3C_IF]); + + api_I3C_Master_Stop((uint32_t) pTask); + EXIT_MASTER_ISR(); + return; + } + + if (pTaskInfo->result == I3C_ERR_MR) { + api_I3C_Master_Stop((uint32_t) pTask); + EXIT_MASTER_ISR(); + return; + } + + if (pTaskInfo->result == I3C_ERR_HJ) { + EXIT_MASTER_ISR(); + return; + } + + if (pTask->protocol == I3C_TRANSFER_PROTOCOL_ENTDAA) { + if (pTaskInfo->result == I3C_ERR_NACK) { + } + + *pTask->pRdLen = pTask->frame_idx * 9; + + pTaskInfo->result = I3C_ERR_OK; + api_I3C_Master_End_Request((uint32_t) pTask); + EXIT_MASTER_ISR(); + return; + } + + if (pFrame->flag & I3C_TRANSFER_NO_STOP) { + api_I3C_Master_Run_Next_Frame((uint32_t) pTask); + EXIT_MASTER_ISR(); + return; + } + + pTaskInfo->result = I3C_ERR_OK; + + if (pTask->protocol == I3C_TRANSFER_PROTOCOL_CCCr) { + pFrame = &pTask->pFrameList[0]; + if ((pFrame->address == I3C_BROADCAST_ADDR) && + (pFrame->direction == I3C_TRANSFER_DIR_WRITE) && + (pFrame->access_buf[0] == CCC_DIRECT_GETACCMST)) { + api_I3C_Master_End_Request((uint32_t) pTask); + + I3C_SET_REG_MCONFIG(I3C_IF, I3C_GET_REG_MCONFIG(I3C_IF) & + ~I3C_MCONFIG_MSTENA_MASK); + I3C_SET_REG_MCONFIG(I3C_IF, I3C_GET_REG_MCONFIG(I3C_IF) | + I3C_MCONFIG_MSTENA(I3C_MCONFIG_MSTENA_MASTER_CAPABLE)); + + I3C_SET_REG_CONFIG(I3C_IF, I3C_GET_REG_CONFIG(I3C_IF) | + I3C_CONFIG_SLVENA_MASK); + + pDevice->mode = I3C_DEVICE_MODE_SECONDARY_MASTER; + EXIT_MASTER_ISR(); + return; + } + } + + api_I3C_Master_Stop((uint32_t) pTask); + EXIT_MASTER_ISR(); + return; + } + + if (mintmask & I3C_MINTMASKED_NOWMASTER_MASK) { + I3C_SET_REG_MSTATUS(I3C_IF, I3C_MSTATUS_NOWMASTER_MASK | I3C_MSTATUS_SLVSTART_MASK); + + pDevice = api_I3C_Get_INODE(I3C_IF); + pDevice->mode = I3C_DEVICE_MODE_CURRENT_MASTER; + pBus->pCurrentMaster = pDevice; + + I3C_SET_REG_STATUS(I3C_IF, I3C_STATUS_EVENT_MASK | I3C_STATUS_CHANDLED_MASK | + I3C_STATUS_STOP_MASK); + I3C_SET_REG_DMACTRL(I3C_IF, I3C_GET_REG_DMACTRL(I3C_IF) & + ~(I3C_DMACTRL_DMATB_MASK | I3C_DMACTRL_DMAFB_MASK)); + I3C_SET_REG_DATACTRL(I3C_IF, I3C_GET_REG_DATACTRL(I3C_IF) | + (I3C_DATACTRL_FLUSHFB_MASK | I3C_DATACTRL_FLUSHTB_MASK)); + I3C_SET_REG_CONFIG(I3C_IF, I3C_GET_REG_CONFIG(I3C_IF) & ~I3C_CONFIG_SLVENA_MASK); + + pTask = pDevice->pTaskListHead; + pTaskInfo = pTask->pTaskInfo; + pFrame = &pTask->pFrameList[pTask->frame_idx]; + + pTaskInfo->result = I3C_ERR_OK; + api_I3C_Master_End_Request((uint32_t) pTask); + } + + /* SLVSTART might asserted right after the current task has complete (STOP). + * So, we should do complete before SLVSTART + */ + if (I3C_GET_REG_MINTMASKED(I3C_IF) & I3C_MINTMASKED_SLVSTART_MASK) { + I3C_SET_REG_MSTATUS(I3C_IF, I3C_MSTATUS_SLVSTART_MASK); + + if (pBus->pCurrentTask != NULL) + pDevice->bAbort = TRUE; + api_I3C_Master_New_Request((uint32_t)I3C_IF); + } + + EXIT_MASTER_ISR(); +} + +void I3C_Slave_ISR(uint8_t I3C_IF) +{ + I3C_DEVICE_INFO_t *pDevice; + I3C_TASK_INFO_t *pTaskInfo; + I3C_TRANSFER_TASK_t *pTask; + I3C_TRANSFER_FRAME_t *pFrame; + uint32_t intmasked; + uint8_t evdet; + uint32_t tmp; + uint32_t errwarn; + + ENTER_SLAVE_ISR(); + + pDevice = api_I3C_Get_INODE(I3C_IF); + intmasked = I3C_GET_REG_INTMASKED(I3C_IF); + + if (intmasked & I3C_INTMASKED_START_MASK) { + evdet = (uint8_t)((I3C_GET_REG_STATUS(I3C_IF) & I3C_STATUS_EVDET_MASK) >> + I3C_STATUS_EVDET_SHIFT); + + /* IBI_NACKED and follow DISEC with RESTART */ + if (evdet == 0x02) { + pTask = pDevice->pTaskListHead; + if (pTask != NULL) { + pTaskInfo = pTask->pTaskInfo; + pTaskInfo->result = I3C_ERR_NACK_SLVSTART; + api_I3C_Slave_End_Request((uint32_t) pTask); + } + } + + I3C_SET_REG_STATUS(I3C_IF, I3C_STATUS_START_MASK); + } + + /* !!! Don't remove to leave ISR after slave wakeup */ + if (intmasked & I3C_INTMASKED_MATCHED_MASK) { + I3C_SET_REG_STATUS(I3C_IF, I3C_INTMASKED_MATCHED_MASK); + } + + if (intmasked & I3C_INTMASKED_CCC_MASK) { + I3C_SET_REG_STATUS(I3C_IF, I3C_STATUS_CCC_MASK); + } + + if (intmasked & I3C_INTMASKED_DDRMATCHED_MASK) { + tmp = I3C_Slave_Register_Access(I3C_IF, slvRxOffset[I3C_IF], + slvRxBuf[I3C_IF], TRUE); + + if (tmp == 0xFFFFFFFC) { + I3C_SET_REG_INTCLR(I3C_IF, I3C_INTCLR_DDRMATCHED_MASK); + } else { + I3C_SET_REG_STATUS(I3C_IF, I3C_STATUS_DDRMATCH_MASK); + } + } + + if (intmasked & I3C_INTMASKED_RXPEND_MASK) { + } + + if (intmasked & I3C_INTMASKED_ERRWARN_MASK) { + errwarn = I3C_GET_REG_ERRWARN(I3C_IF); + + if (errwarn & I3C_ERRWARN_SPAR_MASK) { + I3C_SET_REG_ERRWARN(I3C_IF, I3C_ERRWARN_SPAR_MASK); + } + + if (errwarn & I3C_ERRWARN_URUNNACK_MASK) { + I3C_SET_REG_ERRWARN(I3C_IF, I3C_ERRWARN_URUNNACK_MASK); + if (errwarn == I3C_ERRWARN_URUNNACK_MASK) { + EXIT_SLAVE_ISR(); + return; + } + } + + if (errwarn & I3C_ERRWARN_INVSTART_MASK) { + I3C_SET_REG_ERRWARN(I3C_IF, I3C_ERRWARN_INVSTART_MASK); + if (errwarn & I3C_ERRWARN_INVSTART_MASK) { + EXIT_SLAVE_ISR(); + return; + } + } + + if (errwarn & I3C_ERRWARN_OWRITE_MASK) { + I3C_SET_REG_ERRWARN(I3C_IF, I3C_ERRWARN_OWRITE_MASK); + LOG_INF("@E0"); + } + if (errwarn & I3C_ERRWARN_OREAD_MASK) { + I3C_SET_REG_ERRWARN(I3C_IF, I3C_ERRWARN_OREAD_MASK); + LOG_INF("@E1"); + } + + if (errwarn & I3C_ERRWARN_HCRC_MASK) { + I3C_SET_REG_ERRWARN(I3C_IF, I3C_ERRWARN_HCRC_MASK); + LOG_INF("@E3"); + } + if (errwarn & I3C_ERRWARN_HPAR_MASK) { + I3C_SET_REG_ERRWARN(I3C_IF, I3C_ERRWARN_HPAR_MASK); + LOG_INF("@E4"); + } + if (errwarn & I3C_ERRWARN_ORUN_MASK) { + I3C_SET_REG_ERRWARN(I3C_IF, I3C_ERRWARN_ORUN_MASK); + LOG_INF("@E5"); + } + if (errwarn & I3C_ERRWARN_TERM_MASK) { + I3C_SET_REG_ERRWARN(I3C_IF, I3C_ERRWARN_TERM_MASK); + } + if (errwarn & I3C_ERRWARN_S0S1_MASK) { + I3C_SET_REG_ERRWARN(I3C_IF, I3C_ERRWARN_S0S1_MASK); + LOG_INF("@E7"); + } + if (errwarn & I3C_ERRWARN_URUN_MASK) { + I3C_SET_REG_ERRWARN(I3C_IF, I3C_ERRWARN_URUN_MASK); + LOG_INF("@EA"); + } + } + + if (intmasked & I3C_INTMASKED_STOP_MASK) { + I3C_SET_REG_STATUS(I3C_IF, I3C_STATUS_STOP_MASK); + + pTask = pDevice->pTaskListHead; + if (pTask != NULL) { + pTaskInfo = pTask->pTaskInfo; + pFrame = &pTask->pFrameList[pTask->frame_idx]; + } + + I3C_Slave_Handle_DMA((uint32_t) pDevice); + + if (pDevice->stopSplitRead) { + I3C_SET_REG_DMACTRL(I3C_IF, I3C_GET_REG_DMACTRL(I3C_IF) & + ~I3C_DMACTRL_DMATB_MASK); + PDMA->CHCTL &= ~MaskBit(PDMA_OFFSET + I3C_IF); + + if (PDMA->TDSTS & MaskBit(PDMA_OFFSET + I3C_IF)) { + PDMA->TDSTS = MaskBit(PDMA_OFFSET + I3C_IF); + } else { + } + + I3C_SET_REG_DATACTRL(I3C_IF, I3C_GET_REG_DATACTRL(I3C_IF) | + I3C_DATACTRL_FLUSHTB_MASK); + } else { + } + + if (I3C_GET_REG_STATUS(I3C_IF) & I3C_STATUS_EVENT_MASK) { + I3C_SET_REG_STATUS(I3C_IF, I3C_STATUS_EVENT_MASK); + if (pTask->protocol == I3C_TRANSFER_PROTOCOL_MASTER_REQUEST) { + } else { + if (pTaskInfo != NULL) { + pTaskInfo->result = I3C_ERR_OK; + api_I3C_Slave_End_Request((uint32_t) pTask); + } + } + } else if ((pTask != NULL) && ((I3C_GET_REG_STATUS(I3C_IF) & + I3C_STATUS_EVDET_MASK) == I3C_STATUS_EVDET(2))) { + if ((pFrame->flag & I3C_TRANSFER_RETRY_ENABLE) && + (pFrame->retry_count >= 1)) { + pFrame->retry_count--; + api_I3C_Slave_Start_Request((uint32_t) pTaskInfo); + } else { + I3C_SET_REG_CTRL(I3C_IF, I3C_MCTRL_REQUEST_NONE); + + pTaskInfo->result = I3C_ERR_NACK; + api_I3C_Slave_End_Request((uint32_t) pTask); + } + } + + if (I3C_GET_REG_STATUS(I3C_IF) & I3C_STATUS_CHANDLED_MASK) + I3C_SET_REG_STATUS(I3C_IF, I3C_STATUS_CHANDLED_MASK); + if (I3C_GET_REG_STATUS(I3C_IF) & I3C_STATUS_MATCHED_MASK) + I3C_SET_REG_STATUS(I3C_IF, I3C_STATUS_MATCHED_MASK); + if (I3C_GET_REG_STATUS(I3C_IF) & I3C_STATUS_DDRMATCH_MASK) { + I3C_SET_REG_STATUS(I3C_IF, I3C_STATUS_DDRMATCH_MASK); + I3C_SET_REG_INTSET(I3C_IF, I3C_INTSET_DDRMATCHED_MASK); + } + + if (I3C_GET_REG_STATUS(I3C_IF) & I3C_STATUS_DACHG_MASK) { + I3C_Update_Dynamic_Address((uint32_t) I3C_IF); + I3C_SET_REG_STATUS(I3C_IF, I3C_STATUS_DACHG_MASK); + } + + if (I3C_GET_REG_STATUS(I3C_IF) & (I3C_STATUS_START_MASK | I3C_STATUS_STOP_MASK)) + LOG_INF("\r\nRE-ENTRY\r\n"); + + I3C_Prepare_To_Read_Command((uint32_t) I3C_IF); + } + + EXIT_SLAVE_ISR(); +} + +void I3C_Slave_Handle_DMA(__u32 Parm) +{ + +} + +I3C_ErrCode_Enum GetRegisterIndex(I3C_DEVICE_INFO_t *pDevice, uint16_t rx_cnt, uint8_t *pRx_buff, + uint8_t *pIndexRet) +{ + uint8_t reg_count; + uint8_t reg_chk_count; + uint8_t i; + __u16 cmd16; + + if (pIndexRet == NULL) + return I3C_ERR_PARAMETER_INVALID; + + *pIndexRet = 0; + reg_count = sizeof(pDevice->pReg) / sizeof(I3C_REG_ITEM_t *); + reg_chk_count = 0; + + for (i = 0; i < reg_count; i++) { + if (rx_cnt < GetCmdWidth(pDevice->pReg[i].attr.width)) + continue; + reg_chk_count++; + + if (GetCmdWidth(pDevice->pReg[i].attr.width) == 1) { + if (pDevice->pReg[i].cmd.cmd8 == pRx_buff[0]) { + *pIndexRet = i; + return I3C_ERR_OK; + } + + continue; + } + + if (GetCmdWidth(pDevice->pReg[i].attr.width) == 2) { + if (pDevice->pReg[i].attr.endian == 0) + cmd16 = (__u16)pRx_buff[0] | (__u16)pRx_buff[1] << 8; + else + cmd16 = (__u16)pRx_buff[0] << 8 | (__u16)pRx_buff[1]; + + if (pDevice->pReg[i].cmd.cmd16 == cmd16) { + *pIndexRet = i; + return I3C_ERR_OK; + } + + continue; + } + + continue; + } + + /* master send invalid "index" */ + if (reg_chk_count == reg_count) + return I3C_ERR_DATA_ERROR; + + return I3C_ERR_PENDING; +} + +static void i3c_npcm4xx_isr(const struct device *dev) +{ + struct i3c_npcm4xx_config *config = DEV_CFG(dev); + I3C_PORT_Enum port = config->inst_id; + uint32_t mconfig, sconfig; + + mconfig = sys_read32(I3C_BASE_ADDR(port) + OFFSET_MCONFIG); + if ((mconfig & I3C_MCONFIG_MSTENA_MASK) == I3C_MCONFIG_MSTENA_MASTER_ON) { + I3C_Master_ISR(port); + return; + } + + sconfig = sys_read32(I3C_BASE_ADDR(port) + OFFSET_CONFIG); + if ((sconfig & I3C_CONFIG_SLVENA_MASK) == I3C_CONFIG_SLVENA_SLAVE_ON) { + I3C_Slave_ISR(I3C1_IF); + return; + } +} + +/* + * Usage: Used to validate the register info from the input data + * + * port, data read from which internal device + * rx_cnt, used to pass the length of read data + * pRx_buff, used to pass the address of read data buffer + * pRetInfo, used to return the update offset of register + * pTx_buff, used to return the address of register buffer + * + * return: + * 0 : complete or can't find "Index" now + * 1-255 : valid "Index" + * 0xFFFFFFFB: master send hdrcmd read but "Index" change + * 0xFFFFFFFC: master send hdrcmd write + * 0xFFFFFFFD: master send hdrcmd too fast and slave can't handle them + * 0xFFFFFFFE: Invalid "Index" + * 0xFFFFFFFF: Invalid Parameter + */ +uint32_t I3C_Slave_Register_Access(I3C_PORT_Enum port, uint16_t rx_cnt, uint8_t *pRx_buff, + bool bHDR) +{ + I3C_DEVICE_INFO_t *pDevice = api_I3C_Get_INODE(port); + uint8_t cmd_id, hdrCmd1, hdrCmd2; + I3C_ErrCode_Enum result; + uint32_t tmp32; + + hdrCmd1 = 0; + + if (bHDR) { + tmp32 = I3C_GET_REG_HDRCMD(port); + hdrCmd1 = (uint8_t)(tmp32 & I3C_HDRCMD_CMD0_MASK); + hdrCmd2 = hdrCmd1 & 0x7F; + + if (tmp32 & I3C_HDRCMD_OVFLW_MASK) { + return 0xFFFFFFFD; + } + + if (hdrCmd1 & 0x80) { + if ((tmp32 & I3C_HDRCMD_NEWCMD_MASK) == 0) { + LOG_INF("HDR Read Error !!!\r\n"); + return 0xFFFFFFFF; + } + + if (hdrCmd2 != pDevice->cmdIndex) { + LOG_INF("HDR Read Error: \"Index\" change !!!\r\n"); + return 0xFFFFFFFB; + } else { + return 0; + } + } else { + if (tmp32 & I3C_HDRCMD_NEWCMD_MASK) { + return 0xFFFFFFFC; + } + } + + result = GetRegisterIndex(pDevice, 1, (uint8_t *)&hdrCmd2, &cmd_id); + } else { + result = GetRegisterIndex(pDevice, rx_cnt, pRx_buff, &cmd_id); + } + + if (result == I3C_ERR_PARAMETER_INVALID) + return 0xFFFFFFFF; + if (result == I3C_ERR_DATA_ERROR) + return 0xFFFFFFFE; + if (result == I3C_ERR_PENDING) + return 0; + + pDevice->cmdIndex = cmd_id; + + if ((bHDR && rx_cnt) || (!bHDR && (rx_cnt > + GetCmdWidth(pDevice->pReg[pDevice->cmdIndex].attr.width)))) { + if ((pDevice->pReg[pDevice->cmdIndex].attr.write == 0) || + (bHDR && (hdrCmd1 & 0x80))) { + pDevice->pRxBuf = NULL; + pDevice->rxLen = 0; + pDevice->rxOffset = 0; + return 0; + } + + pDevice->rxLen = pDevice->pReg[pDevice->cmdIndex].len; + pDevice->rxOffset = 0; + if (!bHDR) { + pRx_buff += GetCmdWidth(pDevice->pReg[cmd_id].attr.width); + rx_cnt -= GetCmdWidth(pDevice->pReg[cmd_id].attr.width); + } + + while (rx_cnt) { + if (pDevice->rxOffset >= pDevice->rxLen) + break; + + pDevice->pReg[pDevice->cmdIndex].buf[pDevice->rxOffset] = *pRx_buff; + pDevice->rxOffset++; + pRx_buff++; + rx_cnt--; + } + } + + if (pDevice->pReg[pDevice->cmdIndex].attr.read) { + api_I3C_Slave_Prepare_Response(pDevice, pDevice->pReg[pDevice->cmdIndex].len, + pDevice->pReg[pDevice->cmdIndex].buf); + } else { + api_I3C_Slave_Prepare_Response(pDevice, 0, NULL); + } + + return 0; +} + +static int i3c_npcm4xx_init(const struct device *dev) +{ + struct i3c_npcm4xx_config *config = DEV_CFG(dev); + struct i3c_npcm4xx_obj *obj = DEV_DATA(dev); + I3C_PORT_Enum port = config->inst_id; + I3C_DEVICE_INFO_t *pDevice; + + LOG_INF("size_t=%d, uint32_t=%d\n", sizeof(size_t), sizeof(uint32_t)); + LOG_INF("Base=%x\n", (uint32_t) config->base); + LOG_INF("slave=%d, secondary=%d\n", config->slave, config->secondary); + LOG_INF("i2c_scl_hz=%d, i3c_scl_hz=%d\n", config->i2c_scl_hz, config->i3c_scl_hz); + + obj->dev = dev; + obj->task_count = 0; + obj->pTaskListHead = NULL; + obj->pDevice = &gI3c_dev_node_internal[port]; + + obj->config = config; + obj->hw_dat_free_pos = GENMASK(DEVICE_COUNT_MAX - 1, 0); + + /* update default setting */ + I3C_Port_Default_Setting(port); + + /* to customize device node for different projects */ + pDevice = &gI3c_dev_node_internal[port]; + + /* Update device node by user setting */ + pDevice->disableTimeout = TRUE; + pDevice->vendorID = I3C_GET_REG_VENDORID(port); + + pDevice->bcr = config->bcr; + pDevice->dcr = config->dcr; + pDevice->pid[0] = 0x00; + pDevice->pid[1] = ((port & 0x0F) << 4) | 0x00; + pDevice->pid[2] = 0x00; + pDevice->pid[3] = 0x00; + pDevice->pid[4] = (uint8_t)(pDevice->vendorID << 1); + pDevice->pid[5] = (uint8_t)(pDevice->vendorID >> 7); + + pDevice->staticAddr = config->assigned_addr; + + if (config->slave) { + if (config->secondary) + pDevice->mode = I3C_DEVICE_MODE_SECONDARY_MASTER; + else + pDevice->mode = I3C_DEVICE_MODE_SLAVE_ONLY; + + pDevice->callback = I3C_Slave_Callback; + } else { + pDevice->mode = I3C_DEVICE_MODE_CURRENT_MASTER; + + pDevice->bRunI3C = TRUE; + pDevice->ackIBI = TRUE; + pDevice->dynamicAddr = config->assigned_addr; + pDevice->callback = I3C_Master_Callback; + } + + api_I3C_connect_bus(port, config->busno); + + hal_I3C_Config_Device(pDevice); + return 0; +} + +#define I3C_NPCM4XX_INIT(n) static int i3c_npcm4xx_config_func_##n(const struct device *dev);\ + static const struct i3c_npcm4xx_config i3c_npcm4xx_config_##n = {\ + .inst_id = DT_INST_PROP_OR(n, instance_id, 0),\ + .assigned_addr = DT_INST_PROP_OR(n, assigned_address, 0),\ + .slave = DT_INST_PROP_OR(n, slave, 0),\ + .secondary = DT_INST_PROP_OR(n, secondary, 0),\ + .bcr = DT_INST_PROP_OR(n, bcr, 0),\ + .dcr = DT_INST_PROP_OR(n, dcr, 0),\ + .busno = DT_INST_PROP_OR(n, busno, I3C_BUS_COUNT_MAX),\ + .i2c_scl_hz = DT_INST_PROP_OR(n, i2c_scl_hz, 0),\ + .i3c_scl_hz = DT_INST_PROP_OR(n, i3c_scl_hz, 0),\ + .base = (struct i3c_reg *)DT_INST_REG_ADDR(n),\ + };\ + static struct i3c_npcm4xx_obj i3c_npcm4xx_obj##n;\ + DEVICE_DT_INST_DEFINE(n, &i3c_npcm4xx_config_func_##n, NULL, &i3c_npcm4xx_obj##n,\ + &i3c_npcm4xx_config_##n, POST_KERNEL,\ + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, NULL);\ + static int i3c_npcm4xx_config_func_##n(const struct device *dev)\ + {\ + int ret;\ + ret = i3c_npcm4xx_init(dev);\ + if (ret < 0) \ + return ret;\ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), i3c_npcm4xx_isr,\ + DEVICE_DT_INST_GET(n), 0);\ + irq_enable(DT_INST_IRQN(n));\ + return 0;\ + } + +DT_INST_FOREACH_STATUS_OKAY(I3C_NPCM4XX_INIT); diff --git a/dts/arm/nuvoton/npcm400f.dtsi b/dts/arm/nuvoton/npcm400f.dtsi index 7559800d7ed0ca..eed14062bfdd46 100644 --- a/dts/arm/nuvoton/npcm400f.dtsi +++ b/dts/arm/nuvoton/npcm400f.dtsi @@ -169,6 +169,24 @@ label = "SPIP"; status = "disabled"; }; + + i3c0: i3c0@40004000 { + compatible = "nuvoton,npcm4xx-i3c"; + instance-id = <0>; + reg = <0x40004000 0x400>; + interrupts = <20 3>; + status = "disabled"; + label = "I3C_0"; + }; + + i3c1: i3c1@40004400 { + compatible = "nuvoton,npcm4xx-i3c"; + instance-id = <1>; + reg = <0x40004400 0x400>; + interrupts = <1 3>; + status = "disabled"; + label = "I3C_1"; + }; }; soc-id { diff --git a/dts/arm/nuvoton/npcm4xx/npcm4xx-pinctrl.dtsi b/dts/arm/nuvoton/npcm4xx/npcm4xx-pinctrl.dtsi index c5a363fdadecc4..24355c73422c0c 100644 --- a/dts/arm/nuvoton/npcm4xx/npcm4xx-pinctrl.dtsi +++ b/dts/arm/nuvoton/npcm4xx/npcm4xx-pinctrl.dtsi @@ -35,4 +35,6 @@ pinctrl_vin3_default: vin3_default {}; pinctrl_spip_default: spip_default{}; pinctrl_spip_quad: spip_quad{}; + pinctrl_i3c0_default: i3c0_default {}; + pinctrl_i3c1_default: i3c1_default {}; }; diff --git a/dts/bindings/i3c/i3c-controller.yaml b/dts/bindings/i3c/i3c-controller.yaml new file mode 100644 index 00000000000000..cfba1e09e3d666 --- /dev/null +++ b/dts/bindings/i3c/i3c-controller.yaml @@ -0,0 +1,20 @@ +# Copyright (c) 2023 Nuvoton Technology Corporation. +# SPDX-License-Identifier: Apache-2.0 + +include: base.yaml + +bus: i3c + +properties: + label: + required: true + i2c-scl-hz: + required: false + type: int + default: 1000000 + description: I2C mode and Open-drain mode SCL frequency in HZ + i3c-scl-hz: + required: false + type: int + default: 12500000 + description: I3C Push-Pull mode SCL frequency in HZ diff --git a/dts/bindings/i3c/nuvoton,npcm4xx-i3c.yaml b/dts/bindings/i3c/nuvoton,npcm4xx-i3c.yaml new file mode 100644 index 00000000000000..6fd310d43b5ccf --- /dev/null +++ b/dts/bindings/i3c/nuvoton,npcm4xx-i3c.yaml @@ -0,0 +1,101 @@ +# Copyright (c) 2023 Nuvoton Technology Corporation. +# SPDX-License-Identifier: Apache-2.0 + +description: NUVOTON I3C + +compatible: "nuvoton,npcm4xx-i3c" + +include: [i3c-controller.yaml, nuvoton-pinctrl.yaml] + +properties: +# specify port number + instance-id: + required: true + type: int + description: Instance ID of the device + +#specify port address (master: dynamic address, slave: assigned address for ENTDAA or static address for SETAASA and SETDASA) + assigned-address: + required: true + type: int + description: | + Dynamic address when playing the role as the main master. Static address when playing the role as the slave. + If extra-gpios exist, the lsb of slave static address will be replaced by the value of extra-gpios. + +# not declare --> master +# declare --> slave + slave: + required: false + type: boolean + description: Initialized as slave / master + +# declare --> secondary master if slave is config + secondary: + required: false + type: boolean + description: Initialized as a secondary master + + manufacture-id: + required: false + type: int + description: PID[47:32] + + part-id: + required: false + type: int + description: PID[31:16] + + vendor-def-id: + required: false + type: int + description: PID[11:0] + + bcr: + required: false + type: int + description: Bus Characteristics Register + + dcr: + required: false + type: int + description: Device Characteristics Register + + busno: + required: false + type: int + description: Bus Number + +# pinctrl + pinctrl-0: + required: true + + extra-gpios: + type: phandle-array + required: false + description: | + Used to add the extra info to identify different BIC by GPIOs. + + ibi-append-pec: + required: false + type: boolean + description: Append PEC byte to the IBI data. Enable this option in slave mode if the master device is AST2600 or AST1030A0. + + priv-xfer-pec: + required: false + type: boolean + description: | + Enable this option in slave mode if the i3c want to communicate with data that have PEC. + The PEC will auto append to the tail of the data when doing private transfer and verify + the PEC when receiving the data from master. + + pid-extra-info: + required: false + type: int + description: | + Extra information of the PID Bits[11:0]. Use to identify the different BIC. + If extra-gpios exist, the extra pid will be replaced by the value of extra-gpios. + + sda-tx-hold-ns: + required: false + type: int + description: The hold time of the SDA with respect to the SCL edge. The unit is in nanosecond. diff --git a/include/drivers/i3c/NPCM4XX/api_i3c.h b/include/drivers/i3c/NPCM4XX/api_i3c.h new file mode 100644 index 00000000000000..b49113fc65d99d --- /dev/null +++ b/include/drivers/i3c/NPCM4XX/api_i3c.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef API_I3C_H +#define API_I3C_H + +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +/* To Init I3C Bus */ +extern void api_I3C_Reset(__u8 busNo); +extern I3C_ErrCode_Enum api_I3C_START(void); + +extern I3C_ErrCode_Enum api_I3C_bus_reset_done(__u8 busNo); +extern I3C_ErrCode_Enum api_I3C_bus_clear_done(__u8 busNo); + +extern I3C_ErrCode_Enum api_I3C_connect_bus(I3C_PORT_Enum port, __u8 busNo); +extern I3C_ErrCode_Enum api_I3C_set_pReg(I3C_PORT_Enum port, I3C_REG_ITEM_t *pReg); + +/* Device Node Management */ +extern I3C_DEVICE_INFO_SHORT_t *api_I3C_GetDevInfoByStaticAddr(I3C_BUS_INFO_t *pBus, + __u8 slaveAddr); +extern I3C_DEVICE_INFO_SHORT_t *api_I3C_GetDevInfoByDynamicAddr(I3C_BUS_INFO_t *pBus, + __u8 slaveAddr); + +extern I3C_DEVICE_INFO_t *api_I3C_Get_INODE(I3C_PORT_Enum port); +extern I3C_PORT_Enum api_I3C_Get_IPORT(I3C_DEVICE_INFO_t *pDevice); + +extern I3C_DEVICE_INFO_t *api_I3C_Get_Current_Master_From_Port(I3C_PORT_Enum port); +extern I3C_BUS_INFO_t *api_I3C_Get_Bus_From_Port(I3C_PORT_Enum port); + +/* Task Process */ +extern __u8 I3C_Task_Engine(void); + +extern void api_I3C_Master_Start_Request(__u32 Parm); +extern void api_I3C_Master_Stop(__u32 Parm); +extern void api_I3C_Master_Run_Next_Frame(__u32 Parm); + +extern void api_I3C_Master_New_Request(__u32 Parm); +extern void api_I3C_Master_Insert_DISEC_After_IbiNack(__u32 Parm); +extern void api_I3C_Master_IBIACK(__u32 Parm); +extern void api_I3C_Master_Insert_GETACCMST_After_IbiAckMR(__u32 Parm); +extern void api_I3C_Master_Insert_ENTDAA_After_IbiAckHJ(__u32 Parm); + +extern void api_I3C_Master_End_Request(__u32 Parm); + +extern I3C_ErrCode_Enum api_I3C_Master_Callback(__u32 TaskInfo, I3C_ErrCode_Enum ErrDetail); + +extern void api_I3C_Slave_Start_Request(__u32 Parm); + +extern I3C_ErrCode_Enum api_I3C_Slave_Prepare_Response(I3C_DEVICE_INFO_t *pDevice, __u16 wrLen, + __u8 *pWrBuf); +extern I3C_ErrCode_Enum api_I3C_Slave_Update_Pending(I3C_DEVICE_INFO_t *pDevice, __u8 mask); +extern I3C_ErrCode_Enum api_I3C_Slave_Finish_Response(I3C_DEVICE_INFO_t *pDevice); +extern I3C_ErrCode_Enum api_I3C_Slave_Check_Response_Complete(I3C_DEVICE_INFO_t *pDevice); +extern I3C_ErrCode_Enum api_I3C_Slave_Check_IBIDIS(I3C_DEVICE_INFO_t *pDevice, _Bool *bRet); + +extern void api_I3C_Slave_End_Request(__u32 Parm); +extern I3C_ErrCode_Enum api_I3C_Slave_Callback(__u32 TaskInfo, I3C_ErrCode_Enum ErrDetail); + + +/* Task Creation */ +extern I3C_TASK_INFO_t *api_I3C_Master_Create_Task(I3C_TRANSFER_PROTOCOL_Enum Protocol, __u8 Addr, + __u8 HSize, __u16 *pWrCnt, __u16 *pRdCnt, __u8 *WrBuf, __u8 *RdBuf, __u32 Baudrate, + __u32 Timeout, ptrI3C_RetFunc callback, __u8 PortId, I3C_TASK_POLICY_Enum Policy, + _Bool bHIF); +extern I3C_TASK_INFO_t *api_I3C_Slave_Create_Task(I3C_TRANSFER_PROTOCOL_Enum Protocol, __u8 Addr, + __u16 *pWrCnt, __u16 *pRdCnt, __u8 *WrBuf, __u8 *RdBuf, __u32 Timeout, + ptrI3C_RetFunc callback, __u8 PortId, _Bool bHIF); + +extern I3C_ErrCode_Enum api_I3C_Master_Insert_Task_ENTDAA(__u16 rxbuf_size, __u8 *rxbuf, + __u32 Baudrate, __u32 Timeout, ptrI3C_RetFunc callback, __u8 PortId, + I3C_TASK_POLICY_Enum Policy, _Bool bHIF); +extern I3C_ErrCode_Enum api_I3C_Master_Insert_Task_CCCb(__u8 CCC, __u16 buf_size, __u8 *buf, + __u32 Baudrate, __u32 Timeout, ptrI3C_RetFunc callback, __u8 PortId, + I3C_TASK_POLICY_Enum Policy, _Bool bHIF); +extern I3C_ErrCode_Enum api_I3C_Master_Insert_Task_CCCw(__u8 CCC, __u8 HSize, __u16 buf_size, + __u8 *buf, __u32 Baudrate, __u32 Timeout, ptrI3C_RetFunc callback, __u8 PortId, + I3C_TASK_POLICY_Enum Policy, _Bool bHIF); +extern I3C_ErrCode_Enum api_I3C_Master_Insert_Task_CCCr(__u8 CCC, __u8 HSize, __u16 txbuf_size, + __u16 rxbuf_size, __u8 *txbuf, __u8 *rxbuf, __u32 Baudrate, __u32 Timeout, + ptrI3C_RetFunc callback, __u8 PortId, I3C_TASK_POLICY_Enum Policy, _Bool bHIF); + +extern I3C_ErrCode_Enum api_ValidateBuffer(I3C_TRANSFER_PROTOCOL_Enum Protocol, __u8 Address, + __u8 HSize, __u16 WrCnt, __u16 RdCnt, __u8 *WrBuf, __u8 *RdBuf, _Bool bHIF); + +/* DMA */ +extern I3C_ErrCode_Enum api_I3C_Setup_Master_Write_DMA(I3C_DEVICE_INFO_t *pDevice); +extern I3C_ErrCode_Enum api_I3C_Setup_Master_Read_DMA(I3C_DEVICE_INFO_t *pDevice); + +extern I3C_ErrCode_Enum api_I3C_Setup_Slave_Write_DMA(I3C_DEVICE_INFO_t *pDevice); +extern I3C_ErrCode_Enum api_I3C_Setup_Slave_Read_DMA(I3C_DEVICE_INFO_t *pDevice); +extern I3C_ErrCode_Enum api_I3C_Setup_Slave_IBI_DMA(I3C_DEVICE_INFO_t *pDevice); + +#ifdef __cplusplus +} +#endif + +#endif /* End of #ifndef API_I3C_H */ diff --git a/include/drivers/i3c/NPCM4XX/hal_I3C.h b/include/drivers/i3c/NPCM4XX/hal_I3C.h new file mode 100644 index 00000000000000..8b46abd99a0baf --- /dev/null +++ b/include/drivers/i3c/NPCM4XX/hal_I3C.h @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef __HAL_I3C_H__ +#define __HAL_I3C_H__ + +#include +#include + +#if (CHIP_ID_NPCM4XX == 5832) + /*#define I3C_PORT1_MODE I3C_DEVICE_MODE_CURRENT_MASTER*/ + /*#define I3C_PORT1_ADDR 0x20*/ + #define I3C_PORT1_PARTNO 0x12345678 + #define I3C_PORT1_BCR 0x66 + #define I3C_PORT1_DCR 0xCC + /*#define I3C_PORT1_BUSNO 0*/ + + /*#define I3C_PORT2_MODE I3C_DEVICE_MODE_CURRENT_MASTER*/ + /*#define I3C_PORT2_ADDR 0x20*/ + #define I3C_PORT2_PARTNO 0x12345678 + #define I3C_PORT2_BCR 0x66 + #define I3C_PORT2_DCR 0xCC + /*#define I3C_PORT2_BUSNO 1*/ + +#else + #define I3C_PORT1_MODE I3C_DEVICE_MODE_CURRENT_MASTER + #define I3C_PORT1_ADDR 0x20 + #define I3C_PORT1_PARTNO 0x12345678 + #define I3C_PORT1_BCR 0x66 + #define I3C_PORT1_DCR 0xCC + #define I3C_PORT1_BUSNO 0 + + #define I3C_PORT2_MODE I3C_DEVICE_MODE_SLAVE_ONLY + #define I3C_PORT2_ADDR 0x21 + #define I3C_PORT2_PARTNO 0x12345678 + #define I3C_PORT2_BCR 0x66 + #define I3C_PORT2_DCR 0xCC + #define I3C_PORT2_BUSNO 0 + + #define I3C_PORT3_MODE I3C_DEVICE_MODE_CURRENT_MASTER + #define I3C_PORT3_ADDR 0x22 + #define I3C_PORT3_PARTNO 0x12345678 + #define I3C_PORT3_BCR 0x66 + #define I3C_PORT3_DCR 0xCC + #define I3C_PORT3_BUSNO 1 + + #define I3C_PORT4_MODE I3C_DEVICE_MODE_SLAVE_ONLY + #define I3C_PORT4_ADDR 0x23 + #define I3C_PORT4_PARTNO 0x12345678 + #define I3C_PORT4_BCR 0x66 + #define I3C_PORT4_DCR 0xCC + #define I3C_PORT4_BUSNO 1 + + #define I3C_PORT5_MODE I3C_DEVICE_MODE_CURRENT_MASTER + #define I3C_PORT5_ADDR 0x24 + #define I3C_PORT5_PARTNO 0x12345678 + #define I3C_PORT5_BCR 0x66 + #define I3C_PORT5_DCR 0xCC + #define I3C_PORT5_BUSNO 2 + + #define I3C_PORT6_MODE I3C_DEVICE_MODE_SLAVE_ONLY + #define I3C_PORT6_ADDR 0x25 + #define I3C_PORT6_PARTNO 0x12345678 + #define I3C_PORT6_BCR 0x66 + #define I3C_PORT6_DCR 0xCC + #define I3C_PORT6_BUSNO 2 +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* called by I3C_Setup_Internal_Device */ +extern void hal_I3C_Config_Internal_Device(I3C_PORT_Enum port, I3C_DEVICE_INFO_t *pDevice); +extern I3C_ErrCode_Enum hal_I3C_Config_Device(I3C_DEVICE_INFO_t *pDevice); + +extern I3C_ErrCode_Enum hal_I3C_enable_interface(I3C_PORT_Enum Port); +extern I3C_ErrCode_Enum hal_I3C_disable_interface(I3C_PORT_Enum Port); + +extern I3C_ErrCode_Enum hal_I3C_enable_interrupt(I3C_PORT_Enum Port); +extern I3C_ErrCode_Enum hal_I3C_disable_interrupt(I3C_PORT_Enum Port); + +extern __u32 hal_I3C_get_mstatus(I3C_PORT_Enum Port); +extern void hal_I3C_set_mstatus(I3C_PORT_Enum Port, __u32 val); +extern I3C_IBITYPE_Enum hal_I3C_get_ibiType(I3C_PORT_Enum Port); +extern __u8 hal_I3C_get_ibiAddr(I3C_PORT_Enum Port); +extern _Bool hal_I3C_Is_Master_Idle(I3C_PORT_Enum port); +extern _Bool hal_I3C_Is_Slave_Idle(I3C_PORT_Enum port); +extern _Bool hal_I3C_Is_Master_DAA(I3C_PORT_Enum port); +extern _Bool hal_I3C_Is_Slave_DAA(I3C_PORT_Enum port); +extern _Bool hal_I3C_Is_Master_SLVSTART(I3C_PORT_Enum port); +extern _Bool hal_I3C_Is_Slave_SLVSTART(I3C_PORT_Enum port); +extern _Bool hal_I3C_Is_Master_NORMAL(I3C_PORT_Enum port); +extern _Bool hal_I3C_Is_Master_DDR(I3C_PORT_Enum port); + +extern void hal_I3C_Nack_IBI(I3C_PORT_Enum port); +extern void hal_I3C_Ack_IBI_Without_MDB(I3C_PORT_Enum port); +extern void hal_I3C_Ack_IBI_With_MDB(I3C_PORT_Enum port); + +extern void hal_I3C_Disable_Master_TX_DMA(I3C_PORT_Enum port); +extern void hal_I3C_Disable_Master_RX_DMA(I3C_PORT_Enum port); +extern void hal_I3C_Disable_Master_DMA(I3C_PORT_Enum port); +extern void hal_I3C_Reset_Master_TX(I3C_PORT_Enum port); + +extern _Bool hal_I3C_TxFifoNotFull(I3C_PORT_Enum Port); +extern void hal_I3C_WriteByte(I3C_PORT_Enum Port, __u8 val); +extern _Bool hal_I3C_DMA_Write(I3C_PORT_Enum Port, I3C_DEVICE_MODE_Enum mode, + __u8 *txBuf, __u16 txLen); +extern _Bool hal_I3C_DMA_Read(I3C_PORT_Enum Port, I3C_DEVICE_MODE_Enum mode, + __u8 *rxBuf, __u16 rxLen); + +extern __u8 hal_i3c_get_dynamic_address(I3C_PORT_Enum port); + +extern _Bool hal_i3c_get_capability_support_master(I3C_PORT_Enum port); +extern _Bool hal_i3c_get_capability_support_slave(I3C_PORT_Enum port); +extern __u16 hal_i3c_get_capability_Tx_Fifo_Len(I3C_PORT_Enum port); +extern __u16 hal_i3c_get_capability_Rx_Fifo_Len(I3C_PORT_Enum port); +extern _Bool hal_i3c_get_capability_support_DMA(I3C_PORT_Enum port); +extern _Bool hal_i3c_get_capability_support_INT(I3C_PORT_Enum port); +extern _Bool hal_i3c_get_capability_support_DDR(I3C_PORT_Enum port); +extern _Bool hal_i3c_get_capability_support_ASYNC0(I3C_PORT_Enum port); +extern _Bool hal_i3c_get_capability_support_IBI(I3C_PORT_Enum port); +extern _Bool hal_i3c_get_capability_support_Master_Request(I3C_PORT_Enum port); +extern _Bool hal_i3c_get_capability_support_Hot_Join(I3C_PORT_Enum port); +extern _Bool hal_i3c_get_capability_support_Offline(I3C_PORT_Enum port); +extern _Bool hal_i3c_get_capability_support_V10(I3C_PORT_Enum port); +extern _Bool hal_i3c_get_capability_support_V11(I3C_PORT_Enum port); + +extern __u8 hal_I3C_get_event_support_status(I3C_PORT_Enum Port); +extern __u32 hal_I3C_get_status(I3C_PORT_Enum Port); +extern _Bool hal_I3C_run_ASYN0(I3C_PORT_Enum port); + +extern I3C_ErrCode_Enum hal_I3C_Process_Task(I3C_TASK_INFO_t *pTaskInfo); +extern I3C_ErrCode_Enum hal_I3C_Stop(I3C_PORT_Enum port); + +extern I3C_ErrCode_Enum hal_I3C_Slave_TX_Free(I3C_PORT_Enum port); +extern I3C_ErrCode_Enum hal_I3C_Set_Pending(I3C_PORT_Enum port, __u8 mask); +extern I3C_ErrCode_Enum hal_I3C_Slave_Query_TxLen(I3C_PORT_Enum port, uint16_t *txLen); +extern I3C_ErrCode_Enum hal_I3C_Stop_Slave_TX(I3C_DEVICE_INFO_t *pDevice); + +extern I3C_ErrCode_Enum hal_I3C_Start_IBI(I3C_TASK_INFO_t *pTaskInfo); +extern I3C_ErrCode_Enum hal_I3C_Start_Master_Request(I3C_TASK_INFO_t *pTaskInfo); +extern I3C_ErrCode_Enum hal_I3C_Start_HotJoin(I3C_TASK_INFO_t *pTaskInfo); + +extern void *hal_I3C_MemAlloc(__u32 Size); +extern void hal_I3C_MemFree(void *pv); + +extern void hal_I3C_Master_Stall(I3C_BUS_INFO_t *pBus, I3C_PORT_Enum port); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/drivers/i3c/NPCM4XX/i3c_core.h b/include/drivers/i3c/NPCM4XX/i3c_core.h new file mode 100644 index 00000000000000..b58845ec873d45 --- /dev/null +++ b/include/drivers/i3c/NPCM4XX/i3c_core.h @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef __I3C_CORE_H__ +#define __I3C_CORE_H__ + +#include + +/* + * variable + */ +extern I3C_BUS_INFO_t gBus[]; +extern I3C_DEVICE_INFO_t gI3c_dev_node_internal[]; + +#define MAX_READ_LEN I3C_PAYLOAD_SIZE_MAX +extern uint8_t slvRxBuf[/*I3C_PORT_MAX*/][MAX_READ_LEN]; +extern uint16_t slvRxLen[]; +extern uint16_t slvRxOffset[]; + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* + * Used for project customizztion + */ +extern void I3C_Setup_Internal_Device(void); + extern I3C_DEVICE_INFO_t *I3C_Get_INODE(I3C_PORT_Enum port); + extern I3C_DEVICE_INFO_t *Get_Current_Master_From_Port(I3C_PORT_Enum port); + extern I3C_PORT_Enum I3C_Get_IPORT(I3C_DEVICE_INFO_t *pDevice); + + extern _Bool IsValidDynamicAddress(__u8 addr); + extern _Bool IsValidStaticAddress(__u8 addr); + + extern I3C_ErrCode_Enum I3C_Port_Default_Setting(I3C_PORT_Enum port); + +extern void I3C_Setup_External_Device(void); +extern I3C_ErrCode_Enum I3C_Setup_Bus(void); + + +/* + * Used for bus operations + */ +extern I3C_BUS_INFO_t *Get_Bus_From_BusNo(__u8 busno); +extern I3C_BUS_INFO_t *Get_Bus_From_Port(I3C_PORT_Enum port); + +extern void BUS_RESET_PORT1(void); +extern void BUS_RESET_PORT2(void); +extern void BUS_CLEAR_PORT1(void); +extern void BUS_CLEAR_PORT2(void); + +/* bus status check */ +extern _Bool I3C_IS_BUS_KEEP_IDLE(I3C_BUS_INFO_t *pBus); +extern _Bool I3C_IS_BUS_DURING_DAA(I3C_BUS_INFO_t *pBus); +extern _Bool I3C_IS_BUS_DETECT_SLVSTART(I3C_BUS_INFO_t *pBus); +extern _Bool I3C_IS_BUS_WAIT_STOP_OR_RETRY(I3C_BUS_INFO_t *pBus); + +/* dev info */ +extern I3C_DEVICE_INFO_SHORT_t *NewDevInfo(I3C_BUS_INFO_t *pBus, void *pDevice, + I3C_DEVICE_ATTRIB_t attr, __u8 prefferedAddr, __u8 dynamicAddr, __u8 pid[], + __u8 bcr, __u8 dcr); +extern I3C_DEVICE_INFO_SHORT_t *GetDevInfoByStaticAddr(I3C_BUS_INFO_t *pBus, __u8 slaveAddr); +extern I3C_DEVICE_INFO_SHORT_t *GetDevInfoByDynamicAddr(I3C_BUS_INFO_t *pBus, __u8 slaveAddr); +extern I3C_DEVICE_INFO_SHORT_t *GetDevInfoByTask(I3C_BUS_INFO_t *pBus, I3C_TRANSFER_TASK_t *pTask); + +extern _Bool IS_Internal_DEVICE(void *pDevice); + +extern void I3C_Reset(__u8 busNo); +extern void RemoveDevInfo(I3C_BUS_INFO_t *pBus, I3C_DEVICE_INFO_SHORT_t *pDevInfo); +extern void ResetDevInfo(I3C_BUS_INFO_t *pBus, I3C_DEVICE_INFO_SHORT_t *pDevInfo); + +/* For bus enumeration */ +extern _Bool IS_I3C_DEVICE_PRESENT(I3C_BUS_INFO_t *pBus); +extern _Bool IS_RSTDAA_DEVICE_PRESENT(I3C_BUS_INFO_t *pBus); +extern _Bool IS_SETHID_DEVICE_PRESENT(I3C_BUS_INFO_t *pBus); +extern _Bool IS_SETDASA_DEVICE_PRESENT(I3C_BUS_INFO_t *pBus); +extern _Bool IS_SETAASA_DEVICE_PRESENT(I3C_BUS_INFO_t *pBus); + +/* CCC for bus enumeration */ +extern void I3C_CCCb_ENEC(I3C_BUS_INFO_t *pBus, __u8 mask, I3C_TASK_POLICY_Enum policy); +extern void I3C_CCCb_DISEC(I3C_BUS_INFO_t *pBus, __u8 mask, I3C_TASK_POLICY_Enum policy); +extern void I3C_CCCb_RSTDAA(I3C_BUS_INFO_t *pBus); +extern void I3C_CCCb_ENTDAA(I3C_BUS_INFO_t *pBus); +extern void I3C_CCCb_SETAASA(I3C_BUS_INFO_t *pBus); +extern void I3C_CCCb_SETHID(I3C_BUS_INFO_t *pBus); +extern void I3C_CCCw_ENEC(I3C_BUS_INFO_t *pBus, __u8 addr, __u8 mask, I3C_TASK_POLICY_Enum policy); +extern void I3C_CCCw_DISEC(I3C_BUS_INFO_t *pBus, __u8 addr, __u8 mask, + I3C_TASK_POLICY_Enum policy); +extern void I3C_CCCw_SETDASA(I3C_BUS_INFO_t *pBus); +extern void I3C_CCCw_SETNEWDA(I3C_BUS_INFO_t *pBus, __u8 dyn_addr_old, __u8 dyn_addr_new); + +/* Response */ +extern __u32 I3C_Notify(I3C_TASK_INFO_t *pTaskInfo); + +/* + * Used to limit task amount + */ +#define I3C_TASK_MAX 10 + +extern I3C_TASK_INFO_t *I3C_Master_Create_Task(I3C_TRANSFER_PROTOCOL_Enum Protocol, __u8 Addr, + __u8 HSize, __u16 *pWrCnt, __u16 *pRdCnt, __u8 *WrBuf, __u8 *RdBuf, __u32 Baudrate, + __u32 Timeout, ptrI3C_RetFunc callback, __u8 PortId, I3C_TASK_POLICY_Enum Policy, + _Bool bHIF); +extern I3C_TASK_INFO_t *I3C_Slave_Create_Task(I3C_TRANSFER_PROTOCOL_Enum Protocol, __u8 Addr, + __u16 *pWrCnt, __u16 *pRdCnt, __u8 *WrBuf, __u8 *RdBuf, __u32 Timeout, + ptrI3C_RetFunc callback, __u8 PortId, _Bool bHIF); +extern void I3C_Complete_Task(I3C_TASK_INFO_t *pTaskInfo); +extern _Bool I3C_Clean_Slave_Task(I3C_DEVICE_INFO_t *pDevice); + +extern void *NewTaskInfo(void); +extern void InitTaskInfo(I3C_TASK_INFO_t *pTaskInfo); +extern void FreeTaskNode(I3C_TRANSFER_TASK_t *pTask); + +extern I3C_ErrCode_Enum ValidateProtocol(I3C_TRANSFER_PROTOCOL_Enum Protocol); +extern I3C_ErrCode_Enum ValidateBaudrate(I3C_TRANSFER_PROTOCOL_Enum Protocol, __u32 BaudRate); +extern I3C_ErrCode_Enum ValidateBuffer(I3C_TRANSFER_PROTOCOL_Enum Protocol, __u8 Address, + __u8 HSize, __u16 WrCnt, __u16 RdCnt, __u8 *WrBuf, __u8 *RdBuf, _Bool bHIF); + +extern I3C_ErrCode_Enum CreateTaskNode(I3C_TASK_INFO_t *pTaskInfo, + I3C_TRANSFER_PROTOCOL_Enum Protocol, __u32 Baudrate, __u8 Addr, __u8 HSize, + __u16 *pWrCnt, __u8 *WrBuf, __u16 *pRdCnt, __u8 *RdBuf, ptrI3C_RetFunc callback, + _Bool bHIF); +extern I3C_ErrCode_Enum InsertTaskNode(I3C_DEVICE_INFO_t *pDevice, + I3C_TRANSFER_TASK_t *pNewTask, __u8 bType); + +/* Sample to create master task and might be used in the driver */ +extern I3C_ErrCode_Enum I3C_Master_Insert_Task_ENTDAA(__u16 rxbuf_size, __u8 *rxbuf, + __u32 Baudrate, __u32 Timeout, ptrI3C_RetFunc callback, __u8 PortId, + I3C_TASK_POLICY_Enum Policy, _Bool bHIF); +extern I3C_ErrCode_Enum I3C_Master_Insert_Task_CCCb(__u8 CCC, __u16 buf_size, __u8 *buf, + __u32 Baudrate, __u32 Timeout, ptrI3C_RetFunc callback, __u8 PortId, + I3C_TASK_POLICY_Enum Policy, _Bool bHIF); +extern I3C_ErrCode_Enum I3C_Master_Insert_Task_CCCw(__u8 CCC, __u8 HSize, + __u16 buf_size, __u8 *buf, __u32 Baudrate, __u32 Timeout, ptrI3C_RetFunc callback, + __u8 PortId, I3C_TASK_POLICY_Enum Policy, _Bool bHIF); +extern I3C_ErrCode_Enum I3C_Master_Insert_Task_CCCr(__u8 CCC, __u8 HSize, + __u16 txbuf_size, __u16 rxbuf_size, __u8 *txbuf, __u8 *rxbuf, __u32 Baudrate, + __u32 Timeout, ptrI3C_RetFunc callback, __u8 PortId, I3C_TASK_POLICY_Enum Policy, + _Bool bHIF); +extern I3C_ErrCode_Enum I3C_Master_Insert_Task_EVENT(__u16 rxbuf_size, __u8 *rxbuf, + __u32 Baudrate, __u32 Timeout, ptrI3C_RetFunc callback, __u8 PortId, + I3C_TASK_POLICY_Enum Policy, _Bool bHIF); + +/* Sample to create slave task and might be used in the driver */ +extern I3C_ErrCode_Enum I3C_Slave_Insert_Task_HotJoin(I3C_PORT_Enum port); +extern I3C_ErrCode_Enum I3C_Slave_Insert_Task_MasterRequest(I3C_PORT_Enum port); +extern I3C_ErrCode_Enum I3C_Slave_Insert_Task_IBI(I3C_PORT_Enum port, + __u16 txbuf_size, __u8 *txbuf); + +/* to support pec */ +/*extern __u8 I3C_crc8_fast(__u8 crc, __u8 const *mem, size_t len);*/ + +#ifdef __cplusplus +} +#endif + +#endif /* __I3C_CORE_H__ */ diff --git a/include/drivers/i3c/NPCM4XX/i3c_drv.h b/include/drivers/i3c/NPCM4XX/i3c_drv.h new file mode 100644 index 00000000000000..ada3e107938a45 --- /dev/null +++ b/include/drivers/i3c/NPCM4XX/i3c_drv.h @@ -0,0 +1,1845 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __I3C_H__ +#define __I3C_H__ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define DT_DRV_COMPAT nuvoton_npcm4xx_i3c + +#define I3C_1MHz_VAL_CONST 1000000UL + +#define APB3_CLK 24000000 /** ARM Peripheral Bus 3 */ + +#define I3C_CLOCK_FREQUENCY APB3_CLK +#define I3C_FCLOCK_FREQUENCY APB3_CLK +#define I3C_CLOCK_SLOW_FREQUENCY APB3_CLK +#define I3C_CLOCK_SLOW_TC_FREQUENCY APB3_CLK + +/* + * define for register + */ + +/* Bus characteristics register information. */ +#define BCR_MASTER_CAPABLE_MASK 0xC0 +#define BCR_HDR_CAPABLE_MASK 0x20 +#define BCR_BRIDGE_CAPABLE_MASK 0x10 +#define BCR_OFFLINE_CAPABLE_MASK 0x08 +#define BCR_MDB_EXIST_MASK 0x04 +#define BCR_IBI_CAPABLE_MASK 0x02 +#define BCR_MAX_SPEED_LIMIT_MASK 0x01 + +#define BCR_MASTER_CAPABLE 0x40 +#define BCR_HDR_CAPABLE 0x20 +#define BCR_BRIDGE_CAPABLE 0x10 +#define BCR_OFFLINE_CAPABLE 0x08 +#define BCR_MDB_EXIST 0x04 +#define BCR_IBI_CAPABLE 0x02 +#define BCR_MAX_SPEED_LIMIT 0x01 + +#define DEVICE_COUNT_MAX 32 + +struct i3c_ibi_status { + uint32_t length; + uint8_t id; + uint8_t last; + uint8_t error; + uint8_t ibi_status; +}; + +struct i3c_npcm4xx_cmd { + uint32_t cmd_lo; + uint32_t cmd_hi; + void *tx_buf; + void *rx_buf; + int tx_length; + int rx_length; + int ret; +}; +struct i3c_npcm4xx_xfer { + int ret; + int ncmds; + struct i3c_npcm4xx_cmd *cmds; + struct k_sem sem; +}; + +struct i3c_npcm4xx_dev_priv { + int pos; + struct { + int enable; + struct i3c_ibi_callbacks *callbacks; + struct i3c_dev_desc *context; + struct i3c_ibi_payload *incomplete; + } ibi; +}; + +struct i3c_npcm4xx_config { + int inst_id; + int assigned_addr; + int bcr; + int dcr; + int busno; + struct i3c_reg *base; + bool slave; + bool secondary; + uint32_t i3c_scl_hz; + uint32_t i2c_scl_hz; + uint16_t pid_extra_info; + int ibi_append_pec; + int priv_xfer_pec; + int sda_tx_hold_ns; + int i3c_pp_scl_hi_period_ns; + int i3c_pp_scl_lo_period_ns; + int i3c_od_scl_hi_period_ns; + int i3c_od_scl_lo_period_ns; +}; + +struct i3c_npcm4xx_obj { + const struct device *dev; + I3C_DEVICE_INFO_t *pDevice; + volatile __u8 task_count; + struct I3C_TRANSFER_TASK *pTaskListHead; + + struct i3c_npcm4xx_config *config; + struct k_spinlock lock; + struct i3c_npcm4xx_xfer *curr_xfer; + struct k_work work; + bool sir_allowed_by_sw; + struct { + uint32_t ibi_status_correct :1; + uint32_t ibi_pec_force_enable :1; + uint32_t reserved :30; + } hw_feature; + + int (*ibi_status_parser)(uint32_t value, struct i3c_ibi_status *result); + + uint32_t hw_dat_free_pos; + uint8_t dev_addr_tbl[DEVICE_COUNT_MAX]; + + struct i3c_dev_desc *dev_descs[DEVICE_COUNT_MAX]; + + /* slave mode data */ + struct i3c_slave_setup slave_data; + osEventFlagsId_t ibi_event; + osEventFlagsId_t data_event; + uint16_t extra_val; +}; + +#define DEV_CFG(dev) ((struct i3c_npcm4xx_config *)(dev)->config) +#define DEV_DATA(dev) ((struct i3c_npcm4xx_obj *)(dev)->data) +#define DESC_PRIV(desc) ((struct i3c_npcm4xx_dev_priv *)(desc)->priv_data) + +enum I3C_REG_OFFSET { + OFFSET_MCONFIG = 0x0, + OFFSET_CONFIG = 0x4, + OFFSET_STATUS = 0x8, + OFFSET_CTRL = 0xC, + OFFSET_INTSET = 0x10, + OFFSET_INTCLR = 0x14, + OFFSET_INTMASKED = 0x18, + OFFSET_ERRWARN = 0x1C, + OFFSET_DMACTRL = 0x20, + OFFSET_DATACTRL = 0x2C, + OFFSET_WDATAB = 0x30, + OFFSET_WDATABE = 0x34, + OFFSET_WDATAH = 0x38, + OFFSET_WDATAHE = 0x3C, + OFFSET_RDATAB = 0x40, + OFFSET_RDATAH = 0x48, + OFFSET_WDATAB1 = 0x54, + OFFSET_CAPABILITIES = 0x60, + OFFSET_DYNADDR = 0x64, + OFFSET_MAXLIMITS = 0x68, + OFFSET_PARTNO = 0x6C, + OFFSET_IDEXT = 0x70, + OFFSET_VENDORID = 0x74, + OFFSET_TCCLOCK = 0x78, + OFFSET_MCTRL = 0x84, + OFFSET_MSTATUS = 0x88, + OFFSET_IBIRULES = 0x8C, + OFFSET_MINTSET = 0x90, + OFFSET_MINTCLR = 0x94, + OFFSET_MINTMASKED = 0x98, + OFFSET_MERRWARN = 0x9C, + OFFSET_MDMACTRL = 0xA0, + OFFSET_MDATACTRL = 0xAC, + OFFSET_MWDATAB = 0xB0, + OFFSET_MWDATABE = 0xB4, + OFFSET_MWDATAH = 0xB8, + OFFSET_MWDATAHE = 0xBC, + OFFSET_MRDATAB = 0xC0, + OFFSET_MRDATAH = 0xC8, + OFFSET_MWDATAB1 = 0xCC, + OFFSET_MWMSG_SDR = 0xD0, + OFFSET_MRMSG_SDR = 0xD4, + OFFSET_MWMSG_DDR = 0xD8, + OFFSET_MRMSG_DDR = 0xDC, + OFFSET_MDYNADDR = 0xE4, + OFFSET_HDRCMD = 0x108, + OFFSET_IBIEXT1 = 0x140, + OFFSET_IBIEXT2 = 0x144, + OFFSET_ID = 0x1FC, +}; + +/* MCONFIG */ +#define I3C_MCONFIG_I2CBAUD_MASK (0xF0000000U) +#define I3C_MCONFIG_I2CBAUD_SHIFT (28U) +#define I3C_MCONFIG_I2CBAUD(x) (((uint32_t)(((uint32_t)(x)) << I3C_MCONFIG_I2CBAUD_SHIFT)) \ +& I3C_MCONFIG_I2CBAUD_MASK) + +#define I3C_MCONFIG_ODHPP_MASK (0x1000000U) +#define I3C_MCONFIG_ODHPP_SHIFT (24U) +#define I3C_MCONFIG_ODHPP(x) (((uint32_t)(((uint32_t)(x)) << I3C_MCONFIG_ODHPP_SHIFT)) \ +& I3C_MCONFIG_ODHPP_MASK) + +#define I3C_MCONFIG_ODBAUD_MASK (0xFF0000U) +#define I3C_MCONFIG_ODBAUD_SHIFT (16U) +#define I3C_MCONFIG_ODBAUD(x) (((uint32_t)(((uint32_t)(x)) << I3C_MCONFIG_ODBAUD_SHIFT)) \ +& I3C_MCONFIG_ODBAUD_MASK) + +#define I3C_MCONFIG_PPLOW_MASK (0xF000U) +#define I3C_MCONFIG_PPLOW_SHIFT (12U) +#define I3C_MCONFIG_PPLOW(x) (((uint32_t)(((uint32_t)(x)) << I3C_MCONFIG_PPLOW_SHIFT)) \ +& I3C_MCONFIG_PPLOW_MASK) + +#define I3C_MCONFIG_PPBAUD_MASK (0xF00U) +#define I3C_MCONFIG_PPBAUD_SHIFT (8U) +#define I3C_MCONFIG_PPBAUD(x) (((uint32_t)(((uint32_t)(x)) << I3C_MCONFIG_PPBAUD_SHIFT)) \ +& I3C_MCONFIG_PPBAUD_MASK) + +#define I3C_MCONFIG_ODSTOP_MASK (0x40U) +#define I3C_MCONFIG_ODSTOP_SHIFT (6U) +#define I3C_MCONFIG_ODSTOP(x) (((uint32_t)(((uint32_t)(x)) << I3C_MCONFIG_ODSTOP_SHIFT)) \ +& I3C_MCONFIG_ODSTOP_MASK) + +#define I3C_MCONFIG_HKEEP_MASK (0x30U) +#define I3C_MCONFIG_HKEEP_SHIFT (4U) +#define I3C_MCONFIG_HKEEP(x) (((uint32_t)(((uint32_t)(x)) << I3C_MCONFIG_HKEEP_SHIFT)) \ +& I3C_MCONFIG_HKEEP_MASK) + +#define I3C_MCONFIG_DISTO_MASK (0x8U) +#define I3C_MCONFIG_DISTO_SHIFT (3U) +#define I3C_MCONFIG_DISTO(x) (((uint32_t)(((uint32_t)(x)) << I3C_MCONFIG_DISTO_SHIFT)) \ +& I3C_MCONFIG_DISTO_MASK) + +#define I3C_MCONFIG_MSTENA_MASK (0x3U) +#define I3C_MCONFIG_MSTENA_SHIFT (0U) +#define I3C_MCONFIG_MSTENA(x) (((uint32_t)(((uint32_t)(x)) << I3C_MCONFIG_MSTENA_SHIFT)) \ +& I3C_MCONFIG_MSTENA_MASK) + +enum I3C_MCONFIG_HKEEP_Enum { + I3C_MCONFIG_HKEEP_NO = 0, + I3C_MCONFIG_HKEEP_ONCHIP = 1, + I3C_MCONFIG_HKEEP_EXTSDA = 2, + I3C_MCONFIG_HKEEP_EXTBOTH = 3, +}; + +enum I3C_MCONFIG_DISTO_Enum { + I3C_MCONFIG_DISTO_OFF = 0, I3C_MCONFIG_DISTO_ON = 1, +}; + +enum I3C_MCONFIG_MSTENA_Enum { + I3C_MCONFIG_MSTENA_MASTER_OFF = 0, + I3C_MCONFIG_MSTENA_MASTER_ON = 1, + I3C_MCONFIG_MSTENA_MASTER_CAPABLE = 2, +}; + +/* MCTRL */ +#define I3C_MCTRL_RDTERM_MASK (0xFF0000U) +#define I3C_MCTRL_RDTERM_SHIFT (16U) +#define I3C_MCTRL_RDTERM(x) (((uint32_t)(((uint32_t)(x)) << I3C_MCTRL_RDTERM_SHIFT)) \ +& I3C_MCTRL_RDTERM_MASK) + +#define I3C_MCTRL_ADDR_MASK (0xFE00U) +#define I3C_MCTRL_ADDR_SHIFT (9U) +#define I3C_MCTRL_ADDR(x) (((uint32_t)(((uint32_t)(x)) << I3C_MCTRL_ADDR_SHIFT)) \ +& I3C_MCTRL_ADDR_MASK) + +#define I3C_MCTRL_DIR_MASK (0x100U) +#define I3C_MCTRL_DIR_SHIFT (8U) +#define I3C_MCTRL_DIR(x) (((uint32_t)(((uint32_t)(x)) << I3C_MCTRL_DIR_SHIFT)) \ +& I3C_MCTRL_DIR_MASK) + +#define I3C_MCTRL_IBIRESP_MASK (0xC0U) +#define I3C_MCTRL_IBIRESP_SHIFT (6U) +#define I3C_MCTRL_IBIRESP(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MCTRL_IBIRESP_SHIFT)) & I3C_MCTRL_IBIRESP_MASK) + +#define I3C_MCTRL_TYPE_MASK (0x30U) +#define I3C_MCTRL_TYPE_SHIFT (4U) +#define I3C_MCTRL_TYPE(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MCTRL_TYPE_SHIFT)) & I3C_MCTRL_TYPE_MASK) + +#define I3C_MCTRL_REQUEST_MASK (0x7U) +#define I3C_MCTRL_REQUEST_SHIFT (0U) +#define I3C_MCTRL_REQUEST(x) (((uint32_t)(((uint32_t)(x)) << I3C_MCTRL_REQUEST_SHIFT)) \ +& I3C_MCTRL_REQUEST_MASK) + +#define I3C_MCTRL_RDTERM_MAX (uint16_t)(I3C_MCTRL_RDTERM_MASK >> I3C_MCTRL_RDTERM_SHIFT) + +enum I3C_MCTRL_DIR_Enum { + I3C_MCTRL_DIR_WRITE = 0, I3C_MCTRL_DIR_READ = 1, +}; + +enum I3C_MCTRL_REQUEST_Enum { + I3C_MCTRL_REQUEST_NONE = 0, + I3C_MCTRL_REQUEST_EMIT_START = 1, + I3C_MCTRL_REQUEST_EMIT_STOP = 2, + I3C_MCTRL_REQUEST_IBI_MANUAL = 3, + I3C_MCTRL_REQUEST_DO_ENTDAA = 4, + I3C_MCTRL_REQUEST_EXIT_DDR = 6, + I3C_MCTRL_REQUEST_IBI_AUTO = 7, +}; + +/* MSTATUS */ +#define I3C_MSTATUS_IBIADDR_MASK (0x7F000000U) +#define I3C_MSTATUS_IBIADDR_SHIFT (24U) +#define I3C_MSTATUS_IBIADDR(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MSTATUS_IBIADDR_SHIFT)) & I3C_MSTATUS_IBIADDR_MASK) + +#define I3C_MSTATUS_NOWMASTER_MASK (0x80000U) +#define I3C_MSTATUS_NOWMASTER_SHIFT (19U) +#define I3C_MSTATUS_NOWMASTER(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MSTATUS_NOWMASTER_SHIFT)) & I3C_MSTATUS_NOWMASTER_MASK) + +#define I3C_MSTATUS_ERRWARN_MASK (0x8000U) +#define I3C_MSTATUS_ERRWARN_SHIFT (15U) +#define I3C_MSTATUS_ERRWARN(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MSTATUS_ERRWARN_SHIFT)) & I3C_MSTATUS_ERRWARN_MASK) + +#define I3C_MSTATUS_IBIWON_MASK (0x2000U) +#define I3C_MSTATUS_IBIWON_SHIFT (13U) +#define I3C_MSTATUS_IBIWON(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MSTATUS_IBIWON_SHIFT)) & I3C_MSTATUS_IBIWON_MASK) + +#define I3C_MSTATUS_TXNOTFULL_MASK (0x1000U) +#define I3C_MSTATUS_TXNOTFULL_SHIFT (12U) +#define I3C_MSTATUS_TXNOTFULL(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MSTATUS_TXNOTFULL_SHIFT)) & I3C_MSTATUS_TXNOTFULL_MASK) + +#define I3C_MSTATUS_RXPEND_MASK (0x800U) +#define I3C_MSTATUS_RXPEND_SHIFT (11U) +#define I3C_MSTATUS_RXPEND(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MSTATUS_RXPEND_SHIFT)) & I3C_MSTATUS_RXPEND_MASK) + +#define I3C_MSTATUS_COMPLETE_MASK (0x400U) +#define I3C_MSTATUS_COMPLETE_SHIFT (10U) +#define I3C_MSTATUS_COMPLETE(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MSTATUS_COMPLETE_SHIFT)) & I3C_MSTATUS_COMPLETE_MASK) + +#define I3C_MSTATUS_MCTRLDONE_MASK (0x200U) +#define I3C_MSTATUS_MCTRLDONE_SHIFT (9U) +#define I3C_MSTATUS_MCTRLDONE(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MSTATUS_MCTRLDONE_SHIFT)) & I3C_MSTATUS_MCTRLDONE_MASK) + +#define I3C_MSTATUS_SLVSTART_MASK (0x100U) +#define I3C_MSTATUS_SLVSTART_SHIFT (8U) +#define I3C_MSTATUS_SLVSTART(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MSTATUS_SLVSTART_SHIFT)) & I3C_MSTATUS_SLVSTART_MASK) + +#define I3C_MSTATUS_IBITYPE_MASK (0xC0U) +#define I3C_MSTATUS_IBITYPE_SHIFT (6U) +#define I3C_MSTATUS_IBITYPE(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MSTATUS_IBITYPE_SHIFT)) & I3C_MSTATUS_IBITYPE_MASK) + +#define I3C_MSTATUS_NACKED_MASK (0x20U) +#define I3C_MSTATUS_NACKED_SHIFT (5U) +#define I3C_MSTATUS_NACKED(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MSTATUS_NACKED_SHIFT)) & I3C_MSTATUS_NACKED_MASK) + +#define I3C_MSTATUS_BETWEEN_MASK (0x10U) +#define I3C_MSTATUS_BETWEEN_SHIFT (4U) +#define I3C_MSTATUS_BETWEEN(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MSTATUS_BETWEEN_SHIFT)) & I3C_MSTATUS_BETWEEN_MASK) + +#define I3C_MSTATUS_STATE_MASK (0x7U) +#define I3C_MSTATUS_STATE_SHIFT (0U) +#define I3C_MSTATUS_STATE(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MSTATUS_STATE_SHIFT)) & I3C_MSTATUS_STATE_MASK) + +enum I3C_MSTATUS_IBITYPE_Enum { + I3C_MSTATUS_IBITYPE_None = 0, + I3C_MSTATUS_IBITYPE_IBI = 1, + I3C_MSTATUS_IBITYPE_MstReq = 2, + I3C_MSTATUS_IBITYPE_HotJoin = 3, +}; + +enum I3C_MSTATUS_STATE_Enum { + I3C_MSTATUS_STATE_IDLE = 0U, + I3C_MSTATUS_STATE_SLVREQ = 1U, + I3C_MSTATUS_STATE_MSGSDR = 2U, + I3C_MSTATUS_STATE_NORMACT = 3U, + I3C_MSTATUS_STATE_DDR = 4U, + I3C_MSTATUS_STATE_DAA = 5U, + I3C_MSTATUS_STATE_IBIACK = 6U, + I3C_MSTATUS_STATE_IBIRCV = 7U, +}; + +/* IBIRULES */ +#define I3C_IBIRULES_NOBYTE_MASK (0x80000000U) +#define I3C_IBIRULES_NOBYTE_SHIFT (31U) +#define I3C_IBIRULES_NOBYTE(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_IBIRULES_NOBYTE_SHIFT)) & I3C_IBIRULES_NOBYTE_MASK) + +#define I3C_IBIRULES_MSB0_MASK (0x40000000U) +#define I3C_IBIRULES_MSB0_SHIFT (30U) +#define I3C_IBIRULES_MSB0(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_IBIRULES_MSB0_SHIFT)) & I3C_IBIRULES_MSB0_MASK) + +#define I3C_IBIRULES_ADDR4_MASK (0x3F000000U) +#define I3C_IBIRULES_ADDR4_SHIFT (24U) +#define I3C_IBIRULES_ADDR4(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_IBIRULES_ADDR4_SHIFT)) & I3C_IBIRULES_ADDR4_MASK) + +#define I3C_IBIRULES_ADDR3_MASK (0xFC0000U) +#define I3C_IBIRULES_ADDR3_SHIFT (18U) +#define I3C_IBIRULES_ADDR3(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_IBIRULES_ADDR3_SHIFT)) & I3C_IBIRULES_ADDR3_MASK) + +#define I3C_IBIRULES_ADDR2_MASK (0x3F000U) +#define I3C_IBIRULES_ADDR2_SHIFT (12U) +#define I3C_IBIRULES_ADDR2(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_IBIRULES_ADDR2_SHIFT)) & I3C_IBIRULES_ADDR2_MASK) + +#define I3C_IBIRULES_ADDR1_MASK (0xFC0U) +#define I3C_IBIRULES_ADDR1_SHIFT (6U) +#define I3C_IBIRULES_ADDR1(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_IBIRULES_ADDR1_SHIFT)) & I3C_IBIRULES_ADDR1_MASK) + +#define I3C_IBIRULES_ADDR0_MASK (0x3FU) +#define I3C_IBIRULES_ADDR0_SHIFT (0U) +#define I3C_IBIRULES_ADDR0(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_IBIRULES_ADDR0_SHIFT)) & I3C_IBIRULES_ADDR0_MASK) + +/* MINTSET */ +#define I3C_MINTSET_NOWMASTER_MASK (0x80000U) +#define I3C_MINTSET_NOWMASTER_SHIFT (19U) +#define I3C_MINTSET_NOWMASTER(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MINTSET_NOWMASTER_SHIFT)) & I3C_MINTSET_NOWMASTER_MASK) + +#define I3C_MINTSET_ERRWARN_MASK (0x8000U) +#define I3C_MINTSET_ERRWARN_SHIFT (15U) +#define I3C_MINTSET_ERRWARN(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MINTSET_ERRWARN_SHIFT)) & I3C_MINTSET_ERRWARN_MASK) + +#define I3C_MINTSET_IBIWON_MASK (0x2000U) +#define I3C_MINTSET_IBIWON_SHIFT (13U) +#define I3C_MINTSET_IBIWON(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MINTSET_IBIWON_SHIFT)) & I3C_MINTSET_IBIWON_MASK) + +#define I3C_MINTSET_TXNOTFULL_MASK (0x1000U) +#define I3C_MINTSET_TXNOTFULL_SHIFT (12U) +#define I3C_MINTSET_TXNOTFULL(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MINTSET_TXNOTFULL_SHIFT)) & I3C_MINTSET_TXNOTFULL_MASK) + +#define I3C_MINTSET_RXPEND_MASK (0x800U) +#define I3C_MINTSET_RXPEND_SHIFT (11U) +#define I3C_MINTSET_RXPEND(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MINTSET_RXPEND_SHIFT)) & I3C_MINTSET_RXPEND_MASK) + +#define I3C_MINTSET_COMPLETE_MASK (0x400U) +#define I3C_MINTSET_COMPLETE_SHIFT (10U) +#define I3C_MINTSET_COMPLETE(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MINTSET_COMPLETE_SHIFT)) & I3C_MINTSET_COMPLETE_MASK) + +#define I3C_MINTSET_MCTRLDONE_MASK (0x200U) +#define I3C_MINTSET_MCTRLDONE_SHIFT (9U) +#define I3C_MINTSET_MCTRLDONE(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MINTSET_MCTRLDONE_SHIFT)) & I3C_MINTSET_MCTRLDONE_MASK) + +#define I3C_MINTSET_SLVSTART_MASK (0x100U) +#define I3C_MINTSET_SLVSTART_SHIFT (8U) +#define I3C_MINTSET_SLVSTART(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MINTSET_SLVSTART_SHIFT)) & I3C_MINTSET_SLVSTART_MASK) + +/* MINTCLR */ +#define I3C_MINTCLR_NOWMASTER_MASK (0x80000U) +#define I3C_MINTCLR_NOWMASTER_SHIFT (19U) +#define I3C_MINTCLR_NOWMASTER(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MINTCLR_NOWMASTER_SHIFT)) & I3C_MINTCLR_NOWMASTER_MASK) + +#define I3C_MINTCLR_ERRWARN_MASK (0x8000U) +#define I3C_MINTCLR_ERRWARN_SHIFT (15U) +#define I3C_MINTCLR_ERRWARN(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MINTCLR_ERRWARN_SHIFT)) & I3C_MINTCLR_ERRWARN_MASK) + +#define I3C_MINTCLR_IBIWON_MASK (0x2000U) +#define I3C_MINTCLR_IBIWON_SHIFT (13U) +#define I3C_MINTCLR_IBIWON(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MINTCLR_IBIWON_SHIFT)) & I3C_MINTCLR_IBIWON_MASK) + +#define I3C_MINTCLR_TXNOTFULL_MASK (0x1000U) +#define I3C_MINTCLR_TXNOTFULL_SHIFT (12U) +#define I3C_MINTCLR_TXNOTFULL(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MINTCLR_TXNOTFULL_SHIFT)) & I3C_MINTCLR_TXNOTFULL_MASK) + +#define I3C_MINTCLR_RXPEND_MASK (0x800U) +#define I3C_MINTCLR_RXPEND_SHIFT (11U) +#define I3C_MINTCLR_RXPEND(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MINTCLR_RXPEND_SHIFT)) & I3C_MINTCLR_RXPEND_MASK) + +#define I3C_MINTCLR_COMPLETE_MASK (0x400U) +#define I3C_MINTCLR_COMPLETE_SHIFT (10U) +#define I3C_MINTCLR_COMPLETE(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MINTCLR_COMPLETE_SHIFT)) & I3C_MINTCLR_COMPLETE_MASK) + +#define I3C_MINTCLR_MCTRLDONE_MASK (0x200U) +#define I3C_MINTCLR_MCTRLDONE_SHIFT (9U) +#define I3C_MINTCLR_MCTRLDONE(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MINTCLR_MCTRLDONE_SHIFT)) & I3C_MINTCLR_MCTRLDONE_MASK) + +#define I3C_MINTCLR_SLVSTART_MASK (0x100U) +#define I3C_MINTCLR_SLVSTART_SHIFT (8U) +#define I3C_MINTCLR_SLVSTART(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MINTCLR_SLVSTART_SHIFT)) & I3C_MINTCLR_SLVSTART_MASK) + +/* MINTMASKED */ +#define I3C_MINTMASKED_NOWMASTER_MASK (0x80000U) +#define I3C_MINTMASKED_NOWMASTER_SHIFT (19U) +#define I3C_MINTMASKED_NOWMASTER(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MINTMASKED_NOWMASTER_SHIFT)) & I3C_MINTMASKED_NOWMASTER_MASK) + +#define I3C_MINTMASKED_ERRWARN_MASK (0x8000U) +#define I3C_MINTMASKED_ERRWARN_SHIFT (15U) +#define I3C_MINTMASKED_ERRWARN(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MINTMASKED_ERRWARN_SHIFT)) & I3C_MINTMASKED_ERRWARN_MASK) + +#define I3C_MINTMASKED_IBIWON_MASK (0x2000U) +#define I3C_MINTMASKED_IBIWON_SHIFT (13U) +#define I3C_MINTMASKED_IBIWON(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MINTMASKED_IBIWON_SHIFT)) & I3C_MINTMASKED_IBIWON_MASK) + +#define I3C_MINTMASKED_TXNOTFULL_MASK (0x1000U) +#define I3C_MINTMASKED_TXNOTFULL_SHIFT (12U) +#define I3C_MINTMASKED_TXNOTFULL(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MINTMASKED_TXNOTFULL_SHIFT)) & I3C_MINTMASKED_TXNOTFULL_MASK) + +#define I3C_MINTMASKED_RXPEND_MASK (0x800U) +#define I3C_MINTMASKED_RXPEND_SHIFT (11U) +#define I3C_MINTMASKED_RXPEND(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MINTMASKED_RXPEND_SHIFT)) & I3C_MINTMASKED_RXPEND_MASK) + +#define I3C_MINTMASKED_COMPLETE_MASK (0x400U) +#define I3C_MINTMASKED_COMPLETE_SHIFT (10U) +#define I3C_MINTMASKED_COMPLETE(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MINTMASKED_COMPLETE_SHIFT)) & I3C_MINTMASKED_COMPLETE_MASK) + +#define I3C_MINTMASKED_MCTRLDONE_MASK (0x200U) +#define I3C_MINTMASKED_MCTRLDONE_SHIFT (9U) +#define I3C_MINTMASKED_MCTRLDONE(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MINTMASKED_MCTRLDONE_SHIFT)) & I3C_MINTMASKED_MCTRLDONE_MASK) + +#define I3C_MINTMASKED_SLVSTART_MASK (0x100U) +#define I3C_MINTMASKED_SLVSTART_SHIFT (8U) +#define I3C_MINTMASKED_SLVSTART(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MINTMASKED_SLVSTART_SHIFT)) & I3C_MINTMASKED_SLVSTART_MASK) + +/* MERRWARN */ +#define I3C_MERRWARN_TIMEOUT_MASK (0x100000U) +#define I3C_MERRWARN_TIMEOUT_SHIFT (20U) +#define I3C_MERRWARN_TIMEOUT(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MERRWARN_TIMEOUT_SHIFT)) & I3C_MERRWARN_TIMEOUT_MASK) + +#define I3C_MERRWARN_INVREQ_MASK (0x80000U) +#define I3C_MERRWARN_INVREQ_SHIFT (19U) +#define I3C_MERRWARN_INVREQ(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MERRWARN_INVREQ_SHIFT)) & I3C_MERRWARN_INVREQ_MASK) + +#define I3C_MERRWARN_MSGERR_MASK (0x40000U) +#define I3C_MERRWARN_MSGERR_SHIFT (18U) +#define I3C_MERRWARN_MSGERR(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MERRWARN_MSGERR_SHIFT)) & I3C_MERRWARN_MSGERR_MASK) + +#define I3C_MERRWARN_OWRITE_MASK (0x20000U) +#define I3C_MERRWARN_OWRITE_SHIFT (17U) +#define I3C_MERRWARN_OWRITE(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MERRWARN_OWRITE_SHIFT)) & I3C_MERRWARN_OWRITE_MASK) + +#define I3C_MERRWARN_OREAD_MASK (0x10000U) +#define I3C_MERRWARN_OREAD_SHIFT (16U) +#define I3C_MERRWARN_OREAD(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MERRWARN_OREAD_SHIFT)) & I3C_MERRWARN_OREAD_MASK) + +#define I3C_MERRWARN_HCRC_MASK (0x400U) +#define I3C_MERRWARN_HCRC_SHIFT (10U) +#define I3C_MERRWARN_HCRC(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MERRWARN_HCRC_SHIFT)) & I3C_MERRWARN_HCRC_MASK) + +#define I3C_MERRWARN_HPAR_MASK (0x200U) +#define I3C_MERRWARN_HPAR_SHIFT (9U) +#define I3C_MERRWARN_HPAR(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MERRWARN_HPAR_SHIFT)) & I3C_MERRWARN_HPAR_MASK) + +#define I3C_MERRWARN_TERM_MASK (0x10U) +#define I3C_MERRWARN_TERM_SHIFT (4U) +#define I3C_MERRWARN_TERM(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MERRWARN_TERM_SHIFT)) & I3C_MERRWARN_TERM_MASK) + +#define I3C_MERRWARN_WRABT_MASK (0x8U) +#define I3C_MERRWARN_WRABT_SHIFT (3U) +#define I3C_MERRWARN_WRABT(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MERRWARN_WRABT_SHIFT)) & I3C_MERRWARN_WRABT_MASK) + +#define I3C_MERRWARN_NACK_MASK (0x4U) +#define I3C_MERRWARN_NACK_SHIFT (2U) +#define I3C_MERRWARN_NACK(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MERRWARN_NACK_SHIFT)) & I3C_MERRWARN_NACK_MASK) + +enum I3C_MERRWARN_Enum { + I3C_MERRWARN_TIMEOUT, + I3C_MERRWARN_INVREQ, + I3C_MERRWARN_MSGERR, + I3C_MERRWARN_OWRITE, + I3C_MERRWARN_OREAD, + I3C_MERRWARN_HCRC, + I3C_MERRWARN_HPAR, + I3C_MERRWARN_TERM, + I3C_MERRWARN_WRABT, + I3C_MERRWARN_NACK, +}; + +/* MDMACTRL */ +#define I3C_MDMACTRL_DMAWIDTH_MASK (0x30U) +#define I3C_MDMACTRL_DMAWIDTH_SHIFT (4U) +#define I3C_MDMACTRL_DMAWIDTH(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MDMACTRL_DMAWIDTH_SHIFT)) & I3C_MDMACTRL_DMAWIDTH_MASK) +#define I3C_MDMACTRL_DMAWIDTH_BYTE (0x01U) +#define I3C_MDMACTRL_DMAWIDTH_HALF_WORD (0x02U) + +#define I3C_MDMACTRL_DMATB_MASK (0xCU) +#define I3C_MDMACTRL_DMATB_SHIFT (2U) +#define I3C_MDMACTRL_DMATB(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MDMACTRL_DMATB_SHIFT)) & I3C_MDMACTRL_DMATB_MASK) + +#define I3C_MDMACTRL_DMAFB_MASK (0x3U) +#define I3C_MDMACTRL_DMAFB_SHIFT (0U) +#define I3C_MDMACTRL_DMAFB(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MDMACTRL_DMAFB_SHIFT)) & I3C_MDMACTRL_DMAFB_MASK) + +/* MDATACTRL */ +#define I3C_MDATACTRL_RXEMPTY_MASK (0x80000000U) +#define I3C_MDATACTRL_RXEMPTY_SHIFT (31U) +#define I3C_MDATACTRL_RXEMPTY(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MDATACTRL_RXEMPTY_SHIFT)) & I3C_MDATACTRL_RXEMPTY_MASK) + +#define I3C_MDATACTRL_TXFULL_MASK (0x40000000U) +#define I3C_MDATACTRL_TXFULL_SHIFT (30U) +#define I3C_MDATACTRL_TXFULL(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MDATACTRL_TXFULL_SHIFT)) & I3C_MDATACTRL_TXFULL_MASK) + +#define I3C_MDATACTRL_RXCOUNT_MASK (0x1F000000U) +#define I3C_MDATACTRL_RXCOUNT_SHIFT (24U) +#define I3C_MDATACTRL_RXCOUNT(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MDATACTRL_RXCOUNT_SHIFT)) & I3C_MDATACTRL_RXCOUNT_MASK) + +#define I3C_MDATACTRL_TXCOUNT_MASK (0x1F0000U) +#define I3C_MDATACTRL_TXCOUNT_SHIFT (16U) +#define I3C_MDATACTRL_TXCOUNT(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MDATACTRL_TXCOUNT_SHIFT)) & I3C_MDATACTRL_TXCOUNT_MASK) + +#define I3C_MDATACTRL_RXTRIG_MASK (0xC0U) +#define I3C_MDATACTRL_RXTRIG_SHIFT (6U) +#define I3C_MDATACTRL_RXTRIG(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MDATACTRL_RXTRIG_SHIFT)) & I3C_MDATACTRL_RXTRIG_MASK) + +#define I3C_MDATACTRL_TXTRIG_MASK (0x30U) +#define I3C_MDATACTRL_TXTRIG_SHIFT (4U) +#define I3C_MDATACTRL_TXTRIG(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MDATACTRL_TXTRIG_SHIFT)) & I3C_MDATACTRL_TXTRIG_MASK) + +#define I3C_MDATACTRL_UNLOCK_MASK (0x4U) +#define I3C_MDATACTRL_UNLOCK_SHIFT (2U) +#define I3C_MDATACTRL_UNLOCK(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MDATACTRL_UNLOCK_SHIFT)) & I3C_MDATACTRL_UNLOCK_MASK) + +#define I3C_MDATACTRL_FLUSHFB_MASK (0x2U) +#define I3C_MDATACTRL_FLUSHFB_SHIFT (1U) +#define I3C_MDATACTRL_FLUSHFB(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MDATACTRL_FLUSHFB_SHIFT)) & I3C_MDATACTRL_FLUSHFB_MASK) + +#define I3C_MDATACTRL_FLUSHTB_MASK (0x1U) +#define I3C_MDATACTRL_FLUSHTB_SHIFT (0U) +#define I3C_MDATACTRL_FLUSHTB(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MDATACTRL_FLUSHTB_SHIFT)) & I3C_MDATACTRL_FLUSHTB_MASK) + +/* MWDATAB */ +#define I3C_MWDATAB_END_A_MASK (0x10000U) +#define I3C_MWDATAB_END_A_SHIFT (16U) +#define I3C_MWDATAB_END_A(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MWDATAB_END_A_SHIFT)) & I3C_MWDATAB_END_A_MASK) + +#define I3C_MWDATAB_END_B_MASK (0x100U) +#define I3C_MWDATAB_END_B_SHIFT (8U) +#define I3C_MWDATAB_END_B(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MWDATAB_END_B_SHIFT)) & I3C_MWDATAB_END_B_MASK) + +#define I3C_MWDATAB_DATA_MASK (0xFFU) +#define I3C_MWDATAB_DATA_SHIFT (0U) +#define I3C_MWDATAB_DATA(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MWDATAB_DATA_SHIFT)) & I3C_MWDATAB_DATA_MASK) + +/* MWDATABE */ +#define I3C_MWDATABE_DATA_MASK (0xFFU) +#define I3C_MWDATABE_DATA_SHIFT (0U) +#define I3C_MWDATABE_DATA(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MWDATABE_DATA_SHIFT)) & I3C_MWDATABE_DATA_MASK) + +/* MWDATAH */ +#define I3C_MWDATAH_END_MASK (0x10000U) +#define I3C_MWDATAH_END_SHIFT (16U) +#define I3C_MWDATAH_END(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MWDATAH_END_SHIFT)) & I3C_MWDATAH_END_MASK) + +#define I3C_MWDATAH_DATA1_MASK (0xFF00U) +#define I3C_MWDATAH_DATA1_SHIFT (8U) +#define I3C_MWDATAH_DATA1(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MWDATAH_DATA1_SHIFT)) & I3C_MWDATAH_DATA1_MASK) + +#define I3C_MWDATAH_DATA0_MASK (0xFFU) +#define I3C_MWDATAH_DATA0_SHIFT (0U) +#define I3C_MWDATAH_DATA0(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MWDATAH_DATA0_SHIFT)) & I3C_MWDATAH_DATA0_MASK) + +/* MWDATAHE */ +#define I3C_MWDATAHE_DATA1_MASK (0xFF00U) +#define I3C_MWDATAHE_DATA1_SHIFT (8U) +#define I3C_MWDATAHE_DATA1(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MWDATAHE_DATA1_SHIFT)) & I3C_MWDATAHE_DATA1_MASK) + +#define I3C_MWDATAHE_DATA0_MASK (0xFFU) +#define I3C_MWDATAHE_DATA0_SHIFT (0U) +#define I3C_MWDATAHE_DATA0(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MWDATAHE_DATA0_SHIFT)) & I3C_MWDATAHE_DATA0_MASK) + +/* MRDATAB */ +#define I3C_MRDATAB_DATA_MASK (0xFFU) +#define I3C_MRDATAB_DATA_SHIFT (0U) +#define I3C_MRDATAB_DATA(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MRDATAB_DATA_SHIFT)) & I3C_MRDATAB_DATA_MASK) + +/* MRDATAH */ +#define I3C_MRDATAH_DATA1_MASK (0xFF00U) +#define I3C_MRDATAH_DATA1_SHIFT (8U) +#define I3C_MRDATAH_DATA1(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MRDATAH_DATA1_SHIFT)) & I3C_MRDATAH_DATA1_MASK) + +#define I3C_MRDATAH_DATA0_MASK (0xFFU) +#define I3C_MRDATAH_DATA0_SHIFT (0U) +#define I3C_MRDATAH_DATA0(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MRDATAH_DATA0_SHIFT)) & I3C_MRDATAH_DATA0_MASK) + +/* MWDATAB1 */ +#define I3C_MWDATAB1_DATA_MASK (0xFFU) +#define I3C_MWDATAB1_DATA_SHIFT (0U) +#define I3C_MWDATAB1_DATA(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MWDATAB1_DATA_SHIFT)) & I3C_MWDATAB1_DATA_MASK) + +/* MWMSG_SDR_CONTROL */ +#define I3C_MWMSG_SDR_CONTROL_LEN_MASK (0xF800U) +#define I3C_MWMSG_SDR_CONTROL_LEN_SHIFT (11U) +#define I3C_MWMSG_SDR_CONTROL_LEN(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MWMSG_SDR_CONTROL_LEN_SHIFT)) & I3C_MWMSG_SDR_CONTROL_LEN_MASK) + +#define I3C_MWMSG_SDR_CONTROL_I2C_MASK (0x400U) +#define I3C_MWMSG_SDR_CONTROL_I2C_SHIFT (10U) +#define I3C_MWMSG_SDR_CONTROL_I2C(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MWMSG_SDR_CONTROL_I2C_SHIFT)) & I3C_MWMSG_SDR_CONTROL_I2C_MASK) + +#define I3C_MWMSG_SDR_CONTROL_END_MASK (0x100U) +#define I3C_MWMSG_SDR_CONTROL_END_SHIFT (8U) +#define I3C_MWMSG_SDR_CONTROL_END(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MWMSG_SDR_CONTROL_END_SHIFT)) & I3C_MWMSG_SDR_CONTROL_END_MASK) + +#define I3C_MWMSG_SDR_CONTROL_ADDR_MASK (0xFEU) +#define I3C_MWMSG_SDR_CONTROL_ADDR_SHIFT (1U) +#define I3C_MWMSG_SDR_CONTROL_ADDR(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MWMSG_SDR_CONTROL_ADDR_SHIFT)) & I3C_MWMSG_SDR_CONTROL_ADDR_MASK) + +#define I3C_MWMSG_SDR_CONTROL_DIR_MASK (0x1U) +#define I3C_MWMSG_SDR_CONTROL_DIR_SHIFT (0U) +#define I3C_MWMSG_SDR_CONTROL_DIR(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MWMSG_SDR_CONTROL_DIR_SHIFT)) & I3C_MWMSG_SDR_CONTROL_DIR_MASK) + +/* MWMSG_SDR_DATA */ +#define I3C_MWMSG_SDR_DATA_DATA16B_MASK (0xFFFFU) +#define I3C_MWMSG_SDR_DATA_DATA16B_SHIFT (0U) +#define I3C_MWMSG_SDR_DATA_DATA16B(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MWMSG_SDR_DATA_DATA16B_SHIFT)) & I3C_MWMSG_SDR_DATA_DATA16B_MASK) + +/* MRMSG_SDR */ +#define I3C_MRMSG_SDR_DATA_MASK (0xFFFFU) +#define I3C_MRMSG_SDR_DATA_SHIFT (0U) +#define I3C_MRMSG_SDR_DATA(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MRMSG_SDR_DATA_SHIFT)) & I3C_MRMSG_SDR_DATA_MASK) + +/* MWMSG_DDR_CONTROL */ +#define I3C_MWMSG_DDR_CONTROL_END_MASK (0x4000U) +#define I3C_MWMSG_DDR_CONTROL_END_SHIFT (14U) +#define I3C_MWMSG_DDR_CONTROL_END(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MWMSG_DDR_CONTROL_END_SHIFT)) & I3C_MWMSG_DDR_CONTROL_END_MASK) + +#define I3C_MWMSG_DDR_CONTROL_LEN_MASK (0x3FFU) +#define I3C_MWMSG_DDR_CONTROL_LEN_SHIFT (0U) +#define I3C_MWMSG_DDR_CONTROL_LEN(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MWMSG_DDR_CONTROL_LEN_SHIFT)) & I3C_MWMSG_DDR_CONTROL_LEN_MASK) + +#define I3C_MWMSG_DDR_CONTROL_ADDR_MASK (0xFE00U) +#define I3C_MWMSG_DDR_CONTROL_ADDR_SHIFT (9U) +#define I3C_MWMSG_DDR_CONTROL_ADDR(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MWMSG_DDR_CONTROL_ADDR_SHIFT)) & I3C_MWMSG_DDR_CONTROL_ADDR_MASK) + +#define I3C_MWMSG_DDR_CONTROL_DIR_MASK (0x80U) +#define I3C_MWMSG_DDR_CONTROL_DIR_SHIFT (7U) +#define I3C_MWMSG_DDR_CONTROL_DIR(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MWMSG_DDR_CONTROL_DIR_SHIFT)) & I3C_MWMSG_DDR_CONTROL_DIR_MASK) + +#define I3C_MWMSG_DDR_CONTROL_CMD_MASK (0x7FU) +#define I3C_MWMSG_DDR_CONTROL_CMD_SHIFT (0U) +#define I3C_MWMSG_DDR_CONTROL_CMD(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MWMSG_DDR_CONTROL_CMD_SHIFT)) & I3C_MWMSG_DDR_CONTROL_CMD_MASK) + +/* MWMSG_DDR_DATA */ +#define I3C_MWMSG_DDR_DATA_DATA16B_MASK (0xFFFFU) +#define I3C_MWMSG_DDR_DATA_DATA16B_SHIFT (0U) +#define I3C_MWMSG_DDR_DATA_DATA16B(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MWMSG_DDR_DATA_DATA16B_SHIFT)) & I3C_MWMSG_DDR_DATA_DATA16B_MASK) + +/* MRMSG_DDR */ +#define I3C_MRMSG_DDR_DATA_MASK (0xFFFFU) +#define I3C_MRMSG_DDR_DATA_SHIFT (0U) +#define I3C_MRMSG_DDR_DATA(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MRMSG_DDR_DATA_SHIFT)) & I3C_MRMSG_DDR_DATA_MASK) + +/* MDYNADDR */ +#define I3C_MDYNADDR_DADDR_MASK (0xFEU) +#define I3C_MDYNADDR_DADDR_SHIFT (1U) +#define I3C_MDYNADDR_DADDR(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MDYNADDR_DADDR_SHIFT)) & I3C_MDYNADDR_DADDR_MASK) + +#define I3C_MDYNADDR_DAVALID_MASK (0x1U) +#define I3C_MDYNADDR_DAVALID_SHIFT (0U) +#define I3C_MDYNADDR_DAVALID(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MDYNADDR_DAVALID_SHIFT)) & I3C_MDYNADDR_DAVALID_MASK) + +/* HDRCMD */ +#define I3C_HDRCMD_NEWCMD_MASK (0x80000000U) +#define I3C_HDRCMD_NEWCMD_SHIFT (31U) +#define I3C_HDRCMD_NEWCMD(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_HDRCMD_NEWCMD_SHIFT)) & I3C_HDRCMD_NEWCMD_MASK) + +#define I3C_HDRCMD_OVFLW_MASK (0x40000000U) +#define I3C_HDRCMD_OVFLW_SHIFT (30U) +#define I3C_HDRCMD_OVFLW(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_HDRCMD_OVFLW_SHIFT)) & I3C_HDRCMD_OVFLW_MASK) + +#define I3C_HDRCMD_CMD0_MASK (0xFFU) +#define I3C_HDRCMD_CMD0_SHIFT (0U) +#define I3C_HDRCMD_CMD0(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_HDRCMD_CMD0_SHIFT)) & I3C_HDRCMD_CMD0_MASK) + +/* IBIEXT1 */ +#define I3C_IBIEXT1_EXT3_MASK (0xFF000000U) +#define I3C_IBIEXT1_EXT3_SHIFT (24U) +#define I3C_IBIEXT1_EXT3(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_IBIEXT1_EXT3_SHIFT)) & I3C_IBIEXT1_EXT3_MASK) + +#define I3C_IBIEXT1_EXT2_MASK (0xFF0000U) +#define I3C_IBIEXT1_EXT2_SHIFT (16U) +#define I3C_IBIEXT1_EXT2(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_IBIEXT1_EXT2_SHIFT)) & I3C_IBIEXT1_EXT2_MASK) + +#define I3C_IBIEXT1_EXT1_MASK (0xFF00U) +#define I3C_IBIEXT1_EXT1_SHIFT (8U) +#define I3C_IBIEXT1_EXT1(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_IBIEXT1_EXT1_SHIFT)) & I3C_IBIEXT1_EXT1_MASK) + +#define I3C_IBIEXT1_MAX_MASK (0x70U) +#define I3C_IBIEXT1_MAX_SHIFT (4U) +#define I3C_IBIEXT1_MAX(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_IBIEXT1_MAX_SHIFT)) & I3C_IBIEXT1_MAX_MASK) + +#define I3C_IBIEXT1_CNT_MASK (0x7U) +#define I3C_IBIEXT1_CNT_SHIFT (0U) +#define I3C_IBIEXT1_CNT(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_IBIEXT1_CNT_SHIFT)) & I3C_IBIEXT1_CNT_MASK) + +#define I3C_IBIEXT2_EXT7_MASK (0xFF000000U) +#define I3C_IBIEXT2_EXT7_SHIFT (24U) +#define I3C_IBIEXT2_EXT7(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_IBIEXT2_EXT7_SHIFT)) & I3C_IBIEXT2_EXT7_MASK) + +#define I3C_IBIEXT2_EXT6_MASK (0xFF0000U) +#define I3C_IBIEXT2_EXT6_SHIFT (16U) +#define I3C_IBIEXT2_EXT6(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_IBIEXT2_EXT6_SHIFT)) & I3C_IBIEXT2_EXT6_MASK) + +#define I3C_IBIEXT2_EXT5_MASK (0xFF00U) +#define I3C_IBIEXT2_EXT5_SHIFT (8U) +#define I3C_IBIEXT2_EXT5(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_IBIEXT2_EXT5_SHIFT)) & I3C_IBIEXT2_EXT5_MASK) + +#define I3C_IBIEXT2_EXT4_MASK (0xFFU) +#define I3C_IBIEXT2_EXT4_SHIFT (0U) +#define I3C_IBIEXT2_EXT4(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_IBIEXT2_EXT4_SHIFT)) & I3C_IBIEXT2_EXT4_MASK) + +/* SID */ +#define I3C_SID_ID_MASK (0xFFFFFFFFU) +#define I3C_SID_ID_SHIFT (0U) +#define I3C_SID_ID(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_SID_ID_SHIFT)) & I3C_SID_ID_MASK) + +/* CONFIG */ +#define I3C_CONFIG_SADDR_MASK (0xFE000000U) +#define I3C_CONFIG_SADDR_SHIFT (25U) +#define I3C_CONFIG_SADDR(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_CONFIG_SADDR_SHIFT)) & I3C_CONFIG_SADDR_MASK) + +#define I3C_CONFIG_BAMATCH_MASK (0x7F0000U) +#define I3C_CONFIG_BAMATCH_SHIFT (16U) +#define I3C_CONFIG_BAMATCH(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_CONFIG_BAMATCH_SHIFT)) & I3C_CONFIG_BAMATCH_MASK) + +#define I3C_CONFIG_HDRCMD_MASK (0x400U) +#define I3C_CONFIG_HDRCMD_SHIFT (10U) +#define I3C_CONFIG_HDRCMD(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_CONFIG_HDRCMD_SHIFT)) & I3C_CONFIG_HDRCMD_MASK) + +#define I3C_CONFIG_OFFLINE_MASK (0x200U) +#define I3C_CONFIG_OFFLINE_SHIFT (9U) +#define I3C_CONFIG_OFFLINE(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_CONFIG_OFFLINE_SHIFT)) & I3C_CONFIG_OFFLINE_MASK) + +#define I3C_CONFIG_IDRAND_MASK (0x100U) +#define I3C_CONFIG_IDRAND_SHIFT (8U) +#define I3C_CONFIG_IDRAND(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_CONFIG_IDRAND_SHIFT)) & I3C_CONFIG_IDRAND_MASK) + +#define I3C_CONFIG_DDROK_MASK (0x10U) +#define I3C_CONFIG_DDROK_SHIFT (4U) +#define I3C_CONFIG_DDROK(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_CONFIG_DDROK_SHIFT)) & I3C_CONFIG_DDROK_MASK) + +#define I3C_CONFIG_S0IGNORE_MASK (0x8U) +#define I3C_CONFIG_S0IGNORE_SHIFT (3U) +#define I3C_CONFIG_S0IGNORE(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_CONFIG_S0IGNORE_SHIFT)) & I3C_CONFIG_S0IGNORE_MASK) + +#define I3C_CONFIG_MATCHSS_MASK (0x4U) +#define I3C_CONFIG_MATCHSS_SHIFT (2U) +#define I3C_CONFIG_MATCHSS(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_CONFIG_MATCHSS_SHIFT)) & I3C_CONFIG_MATCHSS_MASK) + +#define I3C_CONFIG_NACK_MASK (0x2U) +#define I3C_CONFIG_NACK_SHIFT (1U) +#define I3C_CONFIG_NACK(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_CONFIG_NACK_SHIFT)) & I3C_CONFIG_NACK_MASK) + +#define I3C_CONFIG_SLVENA_MASK (0x1U) +#define I3C_CONFIG_SLVENA_SHIFT (0U) +#define I3C_CONFIG_SLVENA(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_CONFIG_SLVENA_SHIFT)) & I3C_CONFIG_SLVENA_MASK) + +enum I3C_CONFIG_SLVENA_Enum { + I3C_CONFIG_SLVENA_SLAVE_OFF = 0, I3C_CONFIG_SLVENA_SLAVE_ON = 1, +}; + +/* STATUS */ +#define I3C_STATUS_TIMECTRL_MASK (0xC0000000U) +#define I3C_STATUS_TIMECTRL_SHIFT (30U) +#define I3C_STATUS_TIMECTRL(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_STATUS_TIMECTRL_SHIFT)) & I3C_STATUS_TIMECTRL_MASK) + +#define I3C_STATUS_ACTSTATE_MASK (0x30000000U) +#define I3C_STATUS_ACTSTATE_SHIFT (28U) +#define I3C_STATUS_ACTSTATE(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_STATUS_ACTSTATE_SHIFT)) & I3C_STATUS_ACTSTATE_MASK) + +#define I3C_STATUS_HJDIS_MASK (0x8000000U) +#define I3C_STATUS_HJDIS_SHIFT (27U) +#define I3C_STATUS_HJDIS(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_STATUS_HJDIS_SHIFT)) & I3C_STATUS_HJDIS_MASK) + +#define I3C_STATUS_MRDIS_MASK (0x2000000U) +#define I3C_STATUS_MRDIS_SHIFT (25U) +#define I3C_STATUS_MRDIS(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_STATUS_MRDIS_SHIFT)) & I3C_STATUS_MRDIS_MASK) + +#define I3C_STATUS_IBIDIS_MASK (0x1000000U) +#define I3C_STATUS_IBIDIS_SHIFT (24U) +#define I3C_STATUS_IBIDIS(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_STATUS_IBIDIS_SHIFT)) & I3C_STATUS_IBIDIS_MASK) + +#define I3C_STATUS_EVDET_MASK (0x300000U) +#define I3C_STATUS_EVDET_SHIFT (20U) +#define I3C_STATUS_EVDET(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_STATUS_EVDET_SHIFT)) & I3C_STATUS_EVDET_MASK) + +#define I3C_STATUS_EVENT_MASK (0x40000U) +#define I3C_STATUS_EVENT_SHIFT (18U) +#define I3C_STATUS_EVENT(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_STATUS_EVENT_SHIFT)) & I3C_STATUS_EVENT_MASK) + +#define I3C_STATUS_CHANDLED_MASK (0x20000U) +#define I3C_STATUS_CHANDLED_SHIFT (17U) +#define I3C_STATUS_CHANDLED(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_STATUS_CHANDLED_SHIFT)) & I3C_STATUS_CHANDLED_MASK) + +#define I3C_STATUS_DDRMATCH_MASK (0x10000U) +#define I3C_STATUS_DDRMATCH_SHIFT (16U) +#define I3C_STATUS_DDRMATCH(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_STATUS_DDRMATCH_SHIFT)) & I3C_STATUS_DDRMATCH_MASK) + +#define I3C_STATUS_ERRWARN_MASK (0x8000U) +#define I3C_STATUS_ERRWARN_SHIFT (15U) +#define I3C_STATUS_ERRWARN(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_STATUS_ERRWARN_SHIFT)) & I3C_STATUS_ERRWARN_MASK) + +#define I3C_STATUS_CCC_MASK (0x4000U) +#define I3C_STATUS_CCC_SHIFT (14U) +#define I3C_STATUS_CCC(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_STATUS_CCC_SHIFT)) & I3C_STATUS_CCC_MASK) + +#define I3C_STATUS_DACHG_MASK (0x2000U) +#define I3C_STATUS_DACHG_SHIFT (13U) +#define I3C_STATUS_DACHG(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_STATUS_DACHG_SHIFT)) & I3C_STATUS_DACHG_MASK) + +#define I3C_STATUS_TXNOTFULL_MASK (0x1000U) +#define I3C_STATUS_TXNOTFULL_SHIFT (12U) +#define I3C_STATUS_TXNOTFULL(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_STATUS_TXNOTFULL_SHIFT)) & I3C_STATUS_TXNOTFULL_MASK) + +#define I3C_STATUS_RXPEND_MASK (0x800U) +#define I3C_STATUS_RXPEND_SHIFT (11U) +#define I3C_STATUS_RXPEND(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_STATUS_RXPEND_SHIFT)) & I3C_STATUS_RXPEND_MASK) + +#define I3C_STATUS_STOP_MASK (0x400U) +#define I3C_STATUS_STOP_SHIFT (10U) +#define I3C_STATUS_STOP(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_STATUS_STOP_SHIFT)) & I3C_STATUS_STOP_MASK) + +#define I3C_STATUS_MATCHED_MASK (0x200U) +#define I3C_STATUS_MATCHED_SHIFT (9U) +#define I3C_STATUS_MATCHED(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_STATUS_MATCHED_SHIFT)) & I3C_STATUS_MATCHED_MASK) + +#define I3C_STATUS_START_MASK (0x100U) +#define I3C_STATUS_START_SHIFT (8U) +#define I3C_STATUS_START(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_STATUS_START_SHIFT)) & I3C_STATUS_START_MASK) + +#define I3C_STATUS_STHDR_MASK (0x40U) +#define I3C_STATUS_STHDR_SHIFT (6U) +#define I3C_STATUS_STHDR(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_STATUS_STHDR_SHIFT)) & I3C_STATUS_STHDR_MASK) + +#define I3C_STATUS_STDAA_MASK (0x20U) +#define I3C_STATUS_STDAA_SHIFT (5U) +#define I3C_STATUS_STDAA(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_STATUS_STDAA_SHIFT)) & I3C_STATUS_STDAA_MASK) + +#define I3C_STATUS_STREQWR_MASK (0x10U) +#define I3C_STATUS_STREQWR_SHIFT (4U) +#define I3C_STATUS_STREQWR(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_STATUS_STREQWR_SHIFT)) & I3C_STATUS_STREQWR_MASK) + +#define I3C_STATUS_STREQRD_MASK (0x8U) +#define I3C_STATUS_STREQRD_SHIFT (3U) +#define I3C_STATUS_STREQRD(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_STATUS_STREQRD_SHIFT)) & I3C_STATUS_STREQRD_MASK) + +#define I3C_STATUS_STCCCH_MASK (0x4U) +#define I3C_STATUS_STCCCH_SHIFT (2U) +#define I3C_STATUS_STCCCH(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_STATUS_STCCCH_SHIFT)) & I3C_STATUS_STCCCH_MASK) + +#define I3C_STATUS_STMSG_MASK (0x2U) +#define I3C_STATUS_STMSG_SHIFT (1U) +#define I3C_STATUS_STMSG(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_STATUS_STMSG_SHIFT)) & I3C_STATUS_STMSG_MASK) + +#define I3C_STATUS_STNOTSTOP_MASK (0x1U) +#define I3C_STATUS_STNOTSTOP_SHIFT (0U) +#define I3C_STATUS_STNOTSTOP(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_STATUS_STNOTSTOP_SHIFT)) & I3C_STATUS_STNOTSTOP_MASK) + +/* CTRL */ +#define I3C_CTRL_VENDINFO_MASK (0xFF000000U) +#define I3C_CTRL_VENDINFO_SHIFT (24U) +#define I3C_CTRL_VENDINFO(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_CTRL_VENDINFO_SHIFT)) & I3C_CTRL_VENDINFO_MASK) + +#define I3C_CTRL_ACTSTATE_MASK (0x300000U) +#define I3C_CTRL_ACTSTATE_SHIFT (20U) +#define I3C_CTRL_ACTSTATE(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_CTRL_ACTSTATE_SHIFT)) & I3C_CTRL_ACTSTATE_MASK) + +#define I3C_CTRL_PENDINT_MASK (0xF0000U) +#define I3C_CTRL_PENDINT_SHIFT (16U) +#define I3C_CTRL_PENDINT(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_CTRL_PENDINT_SHIFT)) & I3C_CTRL_PENDINT_MASK) + +#define I3C_CTRL_IBIDATA_MASK (0xFF00U) +#define I3C_CTRL_IBIDATA_SHIFT (8U) +#define I3C_CTRL_IBIDATA(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_CTRL_IBIDATA_SHIFT)) & I3C_CTRL_IBIDATA_MASK) + +#define I3C_CTRL_EXTDATA_MASK (0x8U) +#define I3C_CTRL_EXTDATA_SHIFT (3U) +#define I3C_CTRL_EXTDATA(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_CTRL_EXTDATA_SHIFT)) & I3C_CTRL_EXTDATA_MASK) + +#define I3C_CTRL_EVENT_MASK (0x3U) +#define I3C_CTRL_EVENT_SHIFT (0U) +#define I3C_CTRL_EVENT(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_CTRL_EVENT_SHIFT)) & I3C_CTRL_EVENT_MASK) + +/* INTSET */ +#define I3C_INTSET_EVENT_MASK (0x40000U) +#define I3C_INTSET_EVENT_SHIFT (18U) +#define I3C_INTSET_EVENT(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_INTSET_EVENT_SHIFT)) & I3C_INTSET_EVENT_MASK) + +#define I3C_INTSET_CHANDLED_MASK (0x20000U) +#define I3C_INTSET_CHANDLED_SHIFT (17U) +#define I3C_INTSET_CHANDLED(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_INTSET_CHANDLED_SHIFT)) & I3C_INTSET_CHANDLED_MASK) + +#define I3C_INTSET_DDRMATCHED_MASK (0x10000U) +#define I3C_INTSET_DDRMATCHED_SHIFT (16U) +#define I3C_INTSET_DDRMATCHED(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_INTSET_DDRMATCHED_SHIFT)) & I3C_INTSET_DDRMATCHED_MASK) + +#define I3C_INTSET_ERRWARN_MASK (0x8000U) +#define I3C_INTSET_ERRWARN_SHIFT (15U) +#define I3C_INTSET_ERRWARN(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_INTSET_ERRWARN_SHIFT)) & I3C_INTSET_ERRWARN_MASK) + +#define I3C_INTSET_CCC_MASK (0x4000U) +#define I3C_INTSET_CCC_SHIFT (14U) +#define I3C_INTSET_CCC(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_INTSET_CCC_SHIFT)) & I3C_INTSET_CCC_MASK) + +#define I3C_INTSET_DACHG_MASK (0x2000U) +#define I3C_INTSET_DACHG_SHIFT (13U) +#define I3C_INTSET_DACHG(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_INTSET_DACHG_SHIFT)) & I3C_INTSET_DACHG_MASK) + +#define I3C_INTSET_TXNOTFULL_MASK (0x1000U) +#define I3C_INTSET_TXNOTFULL_SHIFT (12U) +#define I3C_INTSET_TXNOTFULL(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_INTSET_TXNOTFULL_SHIFT)) & I3C_INTSET_TXNOTFULL_MASK) + +#define I3C_INTSET_RXPEND_MASK (0x800U) +#define I3C_INTSET_RXPEND_SHIFT (11U) +#define I3C_INTSET_RXPEND(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_INTSET_RXPEND_SHIFT)) & I3C_INTSET_RXPEND_MASK) + +#define I3C_INTSET_STOP_MASK (0x400U) +#define I3C_INTSET_STOP_SHIFT (10U) +#define I3C_INTSET_STOP(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_INTSET_STOP_SHIFT)) & I3C_INTSET_STOP_MASK) + +#define I3C_INTSET_MATCHED_MASK (0x200U) +#define I3C_INTSET_MATCHED_SHIFT (9U) +#define I3C_INTSET_MATCHED(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_INTSET_MATCHED_SHIFT)) & I3C_INTSET_MATCHED_MASK) + +#define I3C_INTSET_START_MASK (0x100U) +#define I3C_INTSET_START_SHIFT (8U) +#define I3C_INTSET_START(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_INTSET_START_SHIFT)) & I3C_INTSET_START_MASK) + +/* INTCLR */ +#define I3C_INTCLR_EVENT_MASK (0x40000U) +#define I3C_INTCLR_EVENT_SHIFT (18U) +#define I3C_INTCLR_EVENT(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_INTCLR_EVENT_SHIFT)) & I3C_INTCLR_EVENT_MASK) + +#define I3C_INTCLR_CHANDLED_MASK (0x20000U) +#define I3C_INTCLR_CHANDLED_SHIFT (17U) +#define I3C_INTCLR_CHANDLED(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_INTCLR_CHANDLED_SHIFT)) & I3C_INTCLR_CHANDLED_MASK) + +#define I3C_INTCLR_DDRMATCHED_MASK (0x10000U) +#define I3C_INTCLR_DDRMATCHED_SHIFT (16U) +#define I3C_INTCLR_DDRMATCHED(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_INTCLR_DDRMATCHED_SHIFT)) & I3C_INTCLR_DDRMATCHED_MASK) + +#define I3C_INTCLR_ERRWARN_MASK (0x8000U) +#define I3C_INTCLR_ERRWARN_SHIFT (15U) +#define I3C_INTCLR_ERRWARN(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_INTCLR_ERRWARN_SHIFT)) & I3C_INTCLR_ERRWARN_MASK) + +#define I3C_INTCLR_CCC_MASK (0x4000U) +#define I3C_INTCLR_CCC_SHIFT (14U) +#define I3C_INTCLR_CCC(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_INTCLR_CCC_SHIFT)) & I3C_INTCLR_CCC_MASK) + +#define I3C_INTCLR_DACHG_MASK (0x2000U) +#define I3C_INTCLR_DACHG_SHIFT (13U) +#define I3C_INTCLR_DACHG(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_INTCLR_DACHG_SHIFT)) & I3C_INTCLR_DACHG_MASK) + +#define I3C_INTCLR_TXNOTFULL_MASK (0x1000U) +#define I3C_INTCLR_TXNOTFULL_SHIFT (12U) +#define I3C_INTCLR_TXNOTFULL(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_INTCLR_TXNOTFULL_SHIFT)) & I3C_INTCLR_TXNOTFULL_MASK) + +#define I3C_INTCLR_RXPEND_MASK (0x800U) +#define I3C_INTCLR_RXPEND_SHIFT (11U) +#define I3C_INTCLR_RXPEND(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_INTCLR_RXPEND_SHIFT)) & I3C_INTCLR_RXPEND_MASK) + +#define I3C_INTCLR_STOP_MASK (0x400U) +#define I3C_INTCLR_STOP_SHIFT (10U) +#define I3C_INTCLR_STOP(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_INTCLR_STOP_SHIFT)) & I3C_INTCLR_STOP_MASK) + +#define I3C_INTCLR_MATCHED_MASK (0x200U) +#define I3C_INTCLR_MATCHED_SHIFT (9U) +#define I3C_INTCLR_MATCHED(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_INTCLR_MATCHED_SHIFT)) & I3C_INTCLR_MATCHED_MASK) + +#define I3C_INTCLR_START_MASK (0x100U) +#define I3C_INTCLR_START_SHIFT (8U) +#define I3C_INTCLR_START(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_INTCLR_START_SHIFT)) & I3C_INTCLR_START_MASK) + +/* INTMASKED */ +#define I3C_INTMASKED_EVENT_MASK (0x40000U) +#define I3C_INTMASKED_EVENT_SHIFT (18U) +#define I3C_INTMASKED_EVENT(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_INTMASKED_EVENT_SHIFT)) & I3C_INTMASKED_EVENT_MASK) + +#define I3C_INTMASKED_CHANDLED_MASK (0x20000U) +#define I3C_INTMASKED_CHANDLED_SHIFT (17U) +#define I3C_INTMASKED_CHANDLED(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_INTMASKED_CHANDLED_SHIFT)) & I3C_INTMASKED_CHANDLED_MASK) + +#define I3C_INTMASKED_DDRMATCHED_MASK (0x10000U) +#define I3C_INTMASKED_DDRMATCHED_SHIFT (16U) +#define I3C_INTMASKED_DDRMATCHED(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_INTMASKED_DDRMATCHED_SHIFT)) & I3C_INTMASKED_DDRMATCHED_MASK) + +#define I3C_INTMASKED_ERRWARN_MASK (0x8000U) +#define I3C_INTMASKED_ERRWARN_SHIFT (15U) +#define I3C_INTMASKED_ERRWARN(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_INTMASKED_ERRWARN_SHIFT)) & I3C_INTMASKED_ERRWARN_MASK) + +#define I3C_INTMASKED_CCC_MASK (0x4000U) +#define I3C_INTMASKED_CCC_SHIFT (14U) +#define I3C_INTMASKED_CCC(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_INTMASKED_CCC_SHIFT)) & I3C_INTMASKED_CCC_MASK) + +#define I3C_INTMASKED_DACHG_MASK (0x2000U) +#define I3C_INTMASKED_DACHG_SHIFT (13U) +#define I3C_INTMASKED_DACHG(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_INTMASKED_DACHG_SHIFT)) & I3C_INTMASKED_DACHG_MASK) + +#define I3C_INTMASKED_TXNOTFULL_MASK (0x1000U) +#define I3C_INTMASKED_TXNOTFULL_SHIFT (12U) +#define I3C_INTMASKED_TXNOTFULL(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_INTMASKED_TXNOTFULL_SHIFT)) & I3C_INTMASKED_TXNOTFULL_MASK) + +#define I3C_INTMASKED_RXPEND_MASK (0x800U) +#define I3C_INTMASKED_RXPEND_SHIFT (11U) +#define I3C_INTMASKED_RXPEND(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_INTMASKED_RXPEND_SHIFT)) & I3C_INTMASKED_RXPEND_MASK) + +#define I3C_INTMASKED_STOP_MASK (0x400U) +#define I3C_INTMASKED_STOP_SHIFT (10U) +#define I3C_INTMASKED_STOP(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_INTMASKED_STOP_SHIFT)) & I3C_INTMASKED_STOP_MASK) + +#define I3C_INTMASKED_MATCHED_MASK (0x200U) +#define I3C_INTMASKED_MATCHED_SHIFT (9U) +#define I3C_INTMASKED_MATCHED(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_INTMASKED_MATCHED_SHIFT)) & I3C_INTMASKED_MATCHED_MASK) + +#define I3C_INTMASKED_START_MASK (0x100U) +#define I3C_INTMASKED_START_SHIFT (8U) +#define I3C_INTMASKED_START(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_INTMASKED_START_SHIFT)) & I3C_INTMASKED_START_MASK) + +/* ERRWARN */ +#define I3C_ERRWARN_OWRITE_MASK (0x20000U) +#define I3C_ERRWARN_OWRITE_SHIFT (17U) +#define I3C_ERRWARN_OWRITE(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_ERRWARN_OWRITE_SHIFT)) & I3C_ERRWARN_OWRITE_MASK) + +#define I3C_ERRWARN_OREAD_MASK (0x10000U) +#define I3C_ERRWARN_OREAD_SHIFT (16U) +#define I3C_ERRWARN_OREAD(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_ERRWARN_OREAD_SHIFT)) & I3C_ERRWARN_OREAD_MASK) + +#define I3C_ERRWARN_S0S1_MASK (0x800U) +#define I3C_ERRWARN_S0S1_SHIFT (11U) +#define I3C_ERRWARN_S0S1(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_ERRWARN_S0S1_SHIFT)) & I3C_ERRWARN_S0S1_MASK) + +#define I3C_ERRWARN_HCRC_MASK (0x400U) +#define I3C_ERRWARN_HCRC_SHIFT (10U) +#define I3C_ERRWARN_HCRC(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_ERRWARN_HCRC_SHIFT)) & I3C_ERRWARN_HCRC_MASK) + +#define I3C_ERRWARN_HPAR_MASK (0x200U) +#define I3C_ERRWARN_HPAR_SHIFT (9U) +#define I3C_ERRWARN_HPAR(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_ERRWARN_HPAR_SHIFT)) & I3C_ERRWARN_HPAR_MASK) + +#define I3C_ERRWARN_SPAR_MASK (0x100U) +#define I3C_ERRWARN_SPAR_SHIFT (8U) +#define I3C_ERRWARN_SPAR(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_ERRWARN_SPAR_SHIFT)) & I3C_ERRWARN_SPAR_MASK) + +#define I3C_ERRWARN_INVSTART_MASK (0x10U) +#define I3C_ERRWARN_INVSTART_SHIFT (4U) +#define I3C_ERRWARN_INVSTART(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_ERRWARN_INVSTART_SHIFT)) & I3C_ERRWARN_INVSTART_MASK) + +#define I3C_ERRWARN_TERM_MASK (0x8U) +#define I3C_ERRWARN_TERM_SHIFT (3U) +#define I3C_ERRWARN_TERM(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_ERRWARN_TERM_SHIFT)) & I3C_ERRWARN_TERM_MASK) + +#define I3C_ERRWARN_URUNNACK_MASK (0x4U) +#define I3C_ERRWARN_URUNNACK_SHIFT (2U) +#define I3C_ERRWARN_URUNNACK(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_ERRWARN_URUNNACK_SHIFT)) & I3C_ERRWARN_URUNNACK_MASK) + +#define I3C_ERRWARN_URUN_MASK (0x2U) +#define I3C_ERRWARN_URUN_SHIFT (1U) +#define I3C_ERRWARN_URUN(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_ERRWARN_URUN_SHIFT)) & I3C_ERRWARN_URUN_MASK) + +#define I3C_ERRWARN_ORUN_MASK (0x1U) +#define I3C_ERRWARN_ORUN_SHIFT (0U) +#define I3C_ERRWARN_ORUN(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_ERRWARN_ORUN_SHIFT)) & I3C_ERRWARN_ORUN_MASK) + +enum I3C_ERRWARN_Enum { + I3C_ERRWARN_OWRITE, + I3C_ERRWARN_OREAD, + I3C_ERRWARN_S0S1, + I3C_ERRWARN_HCRC, + I3C_ERRWARN_HPAR, + I3C_ERRWARN_SPAR, + I3C_ERRWARN_INVSTART, + I3C_ERRWARN_TERM, + I3C_ERRWARN_URUNNACK, + I3C_ERRWARN_URUN, + I3C_ERRWARN_ORUN, +}; + +/* DMACTRL */ +#define I3C_DMACTRL_DMAWIDTH_MASK (0x30U) +#define I3C_DMACTRL_DMAWIDTH_SHIFT (4U) +#define I3C_DMACTRL_DMAWIDTH(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_DMACTRL_DMAWIDTH_SHIFT)) & I3C_DMACTRL_DMAWIDTH_MASK) +#define I3C_DMACTRL_DMAWIDTH_BYTE (0x01U) +#define I3C_DMACTRL_DMAWIDTH_HALF_WORD (0x02U) + +#define I3C_DMACTRL_DMATB_MASK (0xCU) +#define I3C_DMACTRL_DMATB_SHIFT (2U) +#define I3C_DMACTRL_DMATB(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_DMACTRL_DMATB_SHIFT)) & I3C_DMACTRL_DMATB_MASK) + +#define I3C_DMACTRL_DMAFB_MASK (0x3U) +#define I3C_DMACTRL_DMAFB_SHIFT (0U) +#define I3C_DMACTRL_DMAFB(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_DMACTRL_DMAFB_SHIFT)) & I3C_DMACTRL_DMAFB_MASK) + +/* DATACTRL */ +#define I3C_DATACTRL_RXEMPTY_MASK (0x80000000U) +#define I3C_DATACTRL_RXEMPTY_SHIFT (31U) +#define I3C_DATACTRL_RXEMPTY(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_DATACTRL_RXEMPTY_SHIFT)) & I3C_DATACTRL_RXEMPTY_MASK) + +#define I3C_DATACTRL_TXFULL_MASK (0x40000000U) +#define I3C_DATACTRL_TXFULL_SHIFT (30U) +#define I3C_DATACTRL_TXFULL(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_DATACTRL_TXFULL_SHIFT)) & I3C_DATACTRL_TXFULL_MASK) + +#define I3C_DATACTRL_RXCOUNT_MASK (0x1F000000U) +#define I3C_DATACTRL_RXCOUNT_SHIFT (24U) +#define I3C_DATACTRL_RXCOUNT(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_DATACTRL_RXCOUNT_SHIFT)) & I3C_DATACTRL_RXCOUNT_MASK) + +#define I3C_DATACTRL_TXCOUNT_MASK (0x1F0000U) +#define I3C_DATACTRL_TXCOUNT_SHIFT (16U) +#define I3C_DATACTRL_TXCOUNT(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_DATACTRL_TXCOUNT_SHIFT)) & I3C_DATACTRL_TXCOUNT_MASK) + +#define I3C_DATACTRL_RXTRIG_MASK (0xC0U) +#define I3C_DATACTRL_RXTRIG_SHIFT (6U) +#define I3C_DATACTRL_RXTRIG(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_DATACTRL_RXTRIG_SHIFT)) & I3C_DATACTRL_RXTRIG_MASK) + +#define I3C_DATACTRL_TXTRIG_MASK (0x30U) +#define I3C_DATACTRL_TXTRIG_SHIFT (4U) +#define I3C_DATACTRL_TXTRIG(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_DATACTRL_TXTRIG_SHIFT)) & I3C_DATACTRL_TXTRIG_MASK) + +#define I3C_DATACTRL_UNLOCK_MASK (0x8U) +#define I3C_DATACTRL_UNLOCK_SHIFT (3U) +#define I3C_DATACTRL_UNLOCK(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_DATACTRL_UNLOCK_SHIFT)) & I3C_DATACTRL_UNLOCK_MASK) + +#define I3C_DATACTRL_FLUSHFB_MASK (0x2U) +#define I3C_DATACTRL_FLUSHFB_SHIFT (1U) +#define I3C_DATACTRL_FLUSHFB(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_DATACTRL_FLUSHFB_SHIFT)) & I3C_DATACTRL_FLUSHFB_MASK) + +#define I3C_DATACTRL_FLUSHTB_MASK (0x1U) +#define I3C_DATACTRL_FLUSHTB_SHIFT (0U) +#define I3C_DATACTRL_FLUSHTB(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_DATACTRL_FLUSHTB_SHIFT)) & I3C_DATACTRL_FLUSHTB_MASK) + +/* WDATAB */ +#define I3C_WDATAB_END_A_MASK (0x10000U) +#define I3C_WDATAB_END_A_SHIFT (16U) +#define I3C_WDATAB_END_A(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_WDATAB_END_A_SHIFT)) & I3C_WDATAB_END_A_MASK) + +#define I3C_WDATAB_END_B_MASK (0x100U) +#define I3C_WDATAB_END_B_SHIFT (8U) +#define I3C_WDATAB_END_B(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_WDATAB_END_B_SHIFT)) & I3C_WDATAB_END_B_MASK) + +#define I3C_WDATAB_DATA_MASK (0xFFU) +#define I3C_WDATAB_DATA_SHIFT (0U) +#define I3C_WDATAB_DATA(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_WDATAB_DATA_SHIFT)) & I3C_WDATAB_DATA_MASK) + +/* WDATABE */ +#define I3C_WDATABE_DATA_MASK (0xFFU) +#define I3C_WDATABE_DATA_SHIFT (0U) +#define I3C_WDATABE_DATA(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_WDATABE_DATA_SHIFT)) & I3C_WDATABE_DATA_MASK) + +/* WDATAH */ +#define I3C_WDATAH_END_MASK (0x10000U) +#define I3C_WDATAH_END_SHIFT (16U) +#define I3C_WDATAH_END(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_WDATAH_END_SHIFT)) & I3C_WDATAH_END_MASK) + +#define I3C_WDATAH_DATA1_MASK (0xFF00U) +#define I3C_WDATAH_DATA1_SHIFT (8U) +#define I3C_WDATAH_DATA1(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_WDATAH_DATA1_SHIFT)) & I3C_WDATAH_DATA1_MASK) + +#define I3C_WDATAH_DATA0_MASK (0xFFU) +#define I3C_WDATAH_DATA0_SHIFT (0U) +#define I3C_WDATAH_DATA0(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_WDATAH_DATA0_SHIFT)) & I3C_WDATAH_DATA0_MASK) + +/* WDATAHE */ +#define I3C_WDATAHE_DATA1_MASK (0xFF00U) +#define I3C_WDATAHE_DATA1_SHIFT (8U) +#define I3C_WDATAHE_DATA1(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_WDATAHE_DATA1_SHIFT)) & I3C_WDATAHE_DATA1_MASK) + +#define I3C_WDATAHE_DATA0_MASK (0xFFU) +#define I3C_WDATAHE_DATA0_SHIFT (0U) +#define I3C_WDATAHE_DATA0(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_WDATAHE_DATA0_SHIFT)) & I3C_WDATAHE_DATA0_MASK) + +/* RDATAB */ +#define I3C_RDATAB_DATA0_MASK (0xFFU) +#define I3C_RDATAB_DATA0_SHIFT (0U) +#define I3C_RDATAB_DATA0(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_RDATAB_DATA0_SHIFT)) & I3C_RDATAB_DATA0_MASK) + +/* RDATAH */ +#define I3C_RDATAH_DATA1_MASK (0xFF00U) +#define I3C_RDATAH_DATA1_SHIFT (8U) +#define I3C_RDATAH_DATA1(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_RDATAH_DATA1_SHIFT)) & I3C_RDATAH_DATA1_MASK) + +#define I3C_RDATAH_DATA0_MASK (0xFFU) +#define I3C_RDATAH_DATA0_SHIFT (0U) +#define I3C_RDATAH_DATA0(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_RDATAH_DATA0_SHIFT)) & I3C_RDATAH_DATA0_MASK) + +/* WDATAB1 */ +#define I3C_WDATAB1_DATA_MASK (0xFFU) +#define I3C_WDATAB1_DATA_SHIFT (0U) +#define I3C_WDATAB1_DATA(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_WDATAB1_DATA_SHIFT)) & I3C_WDATAB1_DATA_MASK) + +/* CAPABILITIES */ +#define I3C_CAPABILITIES_DMA_MASK (0x80000000U) +#define I3C_CAPABILITIES_DMA_SHIFT (31U) +#define I3C_CAPABILITIES_DMA(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_CAPABILITIES_DMA_SHIFT)) & I3C_CAPABILITIES_DMA_MASK) + +#define I3C_CAPABILITIES_INT_MASK (0x40000000U) +#define I3C_CAPABILITIES_INT_SHIFT (30U) +#define I3C_CAPABILITIES_INT(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_CAPABILITIES_INT_SHIFT)) & I3C_CAPABILITIES_INT_MASK) + +#define I3C_CAPABILITIES_FIFORX_SHIFT (28U) +#define I3C_CAPABILITIES_FIFORX_MASK (0x30000000U) +#define I3C_CAPABILITIES_FIFORX(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_CAPABILITIES_FIFORX_SHIFT)) & I3C_CAPABILITIES_FIFORX_MASK) + +#define I3C_CAPABILITIES_FIFOTX_MASK (0xC000000U) +#define I3C_CAPABILITIES_FIFOTX_SHIFT (26U) +#define I3C_CAPABILITIES_FIFOTX(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_CAPABILITIES_FIFOTX_SHIFT)) & I3C_CAPABILITIES_FIFOTX_MASK) + +#define I3C_CAPABILITIES_EXTFIFO_MASK (0x3800000U) +#define I3C_CAPABILITIES_EXTFIFO_SHIFT (23U) +#define I3C_CAPABILITIES_EXTFIFO(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_CAPABILITIES_EXTFIFO_SHIFT)) & I3C_CAPABILITIES_EXTFIFO_MASK) + +#define I3C_CAPABILITIES_TIMECTRL_MASK (0x200000U) +#define I3C_CAPABILITIES_TIMECTRL_SHIFT (21U) +#define I3C_CAPABILITIES_TIMECTRL(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_CAPABILITIES_TIMECTRL_SHIFT)) & I3C_CAPABILITIES_TIMECTRL_MASK) + +#define I3C_CAPABILITIES_IBI_MR_HJ_MASK (0x1F0000U) +#define I3C_CAPABILITIES_IBI_MR_HJ_SHIFT (16U) +#define I3C_CAPABILITIES_IBI_MR_HJ(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_CAPABILITIES_IBI_MR_HJ_SHIFT)) & I3C_CAPABILITIES_IBI_MR_HJ_MASK) + +#define I3C_CAPABILITIES_BAMATCH_SUPP_MASK (0x100000U) +#define I3C_CAPABILITIES_BAMATCH_SUPP_SHIFT (20U) + +#define I3C_CAPABILITIES_HOTJOIN_SUPP_MASK (0x080000U) +#define I3C_CAPABILITIES_HOTJOIN_SUPP_SHIFT (19U) + +#define I3C_CAPABILITIES_MASTER_REQUEST_SUPP_MASK (0x040000U) +#define I3C_CAPABILITIES_MASTER_REQUEST_SUPP_SHIFT (18U) + +#define I3C_CAPABILITIES_IBI_SUPP_MASK (0x020000U) +#define I3C_CAPABILITIES_IBI_SUPP_SHIFT (17U) + +#define I3C_CAPABILITIES_IBI_PAYLOAD_MASK (0x010000U) +#define I3C_CAPABILITIES_IBI_PAYLOAD_SHIFT (16U) + +#define I3C_CAPABILITIES_CCCHANDLE_MASK (0xF000U) +#define I3C_CAPABILITIES_CCCHANDLE_SHIFT (12U) +#define I3C_CAPABILITIES_CCCHANDLE(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_CAPABILITIES_CCCHANDLE_SHIFT)) & I3C_CAPABILITIES_CCCHANDLE_MASK) + +#define I3C_CAPABILITIES_SADDR_MASK (0xC00U) +#define I3C_CAPABILITIES_SADDR_SHIFT (10U) +#define I3C_CAPABILITIES_SADDR(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_CAPABILITIES_SADDR_SHIFT)) & I3C_CAPABILITIES_SADDR_MASK) + +#define I3C_CAPABILITIES_MASTER_MASK (0x200U) +#define I3C_CAPABILITIES_MASTER_SHIFT (9U) +#define I3C_CAPABILITIES_MASTER(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_SCAPABILITIES_MASTER_SHIFT)) & I3C_SCAPABILITIES_MASTER_MASK) + +#define I3C_CAPABILITIES_HDRSUPP_MASK (0x1C0U) +#define I3C_CAPABILITIES_HDRSUPP_SHIFT (6U) +#define I3C_CAPABILITIES_HDRSUPP(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_CAPABILITIES_HDRSUPP_SHIFT)) & I3C_CAPABILITIES_HDRSUPP_MASK) + +#define I3C_CAPABILITIES_IDREG_MASK (0x3CU) +#define I3C_CAPABILITIES_IDREG_SHIFT (2U) +#define I3C_CAPABILITIES_IDREG(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_CAPABILITIES_IDREG_SHIFT)) & I3C_CAPABILITIES_IDREG_MASK) + +#define I3C_CAPABILITIES_IDENA_MASK (0x3U) +#define I3C_CAPABILITIES_IDENA_SHIFT (0U) +#define I3C_CAPABILITIES_IDENA(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_CAPABILITIES_IDENA_SHIFT)) & I3C_CAPABILITIES_IDENA_MASK) + +/* DYNADDR */ +#define I3C_DYNADDR_DADDR_MASK (0xFEU) +#define I3C_DYNADDR_DADDR_SHIFT (1U) +#define I3C_DYNADDR_DADDR(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_DYNADDR_DADDR_SHIFT)) & I3C_DYNADDR_DADDR_MASK) + +#define I3C_DYNADDR_DAVALID_MASK (0x1U) +#define I3C_DYNADDR_DAVALID_SHIFT (0U) +#define I3C_DYNADDR_DAVALID(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_DYNADDR_DAVALID_SHIFT)) & I3C_DYNADDR_DAVALID_MASK) + +/* MAXLIMITS */ +#define I3C_MAXLIMITS_MAXWR_MASK (0xFFF0000U) +#define I3C_MAXLIMITS_MAXWR_SHIFT (16U) +#define I3C_MAXLIMITS_MAXWR(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MAXLIMITS_MAXWR_SHIFT)) & I3C_MAXLIMITS_MAXWR_MASK) + +#define I3C_MAXLIMITS_MAXRD_MASK (0xFFFU) +#define I3C_MAXLIMITS_MAXRD_SHIFT (0U) +#define I3C_MAXLIMITS_MAXRD(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_MAXLIMITS_MAXRD_SHIFT)) & I3C_MAXLIMITS_MAXRD_MASK) + +/* PARTNO */ +#define I3C_PARTNO_PARTNO_MASK (0xFFFFFFFFU) +#define I3C_PARTNO_PARTNO_SHIFT (0U) +#define I3C_PARTNO_PARTNO(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_PARTNO_PARTNO_SHIFT)) & I3C_PARTNO_PARTNO_MASK) + +/* IDEXT */ +#define I3C_IDEXT_BCR_MASK (0xFF0000U) +#define I3C_IDEXT_BCR_SHIFT (16U) +#define I3C_IDEXT_BCR(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_IDEXT_BCR_SHIFT)) & I3C_IDEXT_BCR_MASK) + +#define I3C_IDEXT_DCR_MASK (0xFF00U) +#define I3C_IDEXT_DCR_SHIFT (8U) +#define I3C_IDEXT_DCR(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_IDEXT_DCR_SHIFT)) & I3C_IDEXT_DCR_MASK) + +/* VENDORID */ +#define I3C_VENDORID_VID_MASK (0x7FFFU) +#define I3C_VENDORID_VID_SHIFT (0U) +#define I3C_VENDORID_VID(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_VENDORID_VID_SHIFT)) & I3C_VENDORID_VID_MASK) + +/* TCCLOCK */ +#define I3C_TCCLOCK_FREQ_MASK (0xFF00U) +#define I3C_TCCLOCK_FREQ_SHIFT (8U) +#define I3C_TCCLOCK_FREQ(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_TCCLOCK_FREQ_SHIFT)) & I3C_TCCLOCK_FREQ_MASK) + +#define I3C_TCCLOCK_ACCURACY_MASK (0xFFU) +#define I3C_TCCLOCK_ACCURACY_SHIFT (0U) +#define I3C_TCCLOCK_ACCURACY(x) (((uint32_t)(((uint32_t)(x)) \ +<< I3C_TCCLOCK_ACCURACY_SHIFT)) & I3C_TCCLOCK_ACCURACY_MASK) + + +#define PDMA_DSCT_CTL_TXCNT_Pos (16) +#define PDMA_DSCT_CTL_TXCNT_Msk (0x3ffful << PDMA_DSCT_CTL_TXCNT_Pos) + +#define PDMA_DSCT_CTL_TXWIDTH_Pos (12) +#define PDMA_DSCT_CTL_TXWIDTH_Msk (0x3ul << PDMA_DSCT_CTL_TXWIDTH_Pos) +#define PDMA_WIDTH_8 0x00000000UL +#define PDMA_WIDTH_16 0x00001000UL +#define PDMA_WIDTH_32 0x00002000UL + +#define PDMA_DSCT_CTL_DAINC_Pos (10) +#define PDMA_DSCT_CTL_DAINC_Msk (0x3ul << PDMA_DSCT_CTL_DAINC_Pos) +#define PDMA_DAR_INC 0x00000000UL +#define PDMA_DAR_FIX 0x00000C00UL + +#define PDMA_DSCT_CTL_SAINC_Pos (8) +#define PDMA_DSCT_CTL_SAINC_Msk (0x3ul << PDMA_DSCT_CTL_SAINC_Pos) +#define PDMA_SAR_INC 0x00000000UL +#define PDMA_SAR_FIX 0x00000300UL + +#define PDMA_DSCT_CTL_TBINTDIS_Pos (7) +#define PDMA_DSCT_CTL_TBINTDIS_Msk (0x1ul << PDMA_DSCT_CTL_TBINTDIS_Pos) + +#define PDMA_DSCT_CTL_BURSIZE_Pos (4) +#define PDMA_DSCT_CTL_BURSIZE_Msk (0x7ul << PDMA_DSCT_CTL_BURSIZE_Pos) +#define PDMA_BURST_128 0x00000000UL +#define PDMA_BURST_64 0x00000010UL +#define PDMA_BURST_32 0x00000020UL +#define PDMA_BURST_16 0x00000030UL +#define PDMA_BURST_8 0x00000040UL +#define PDMA_BURST_4 0x00000050UL +#define PDMA_BURST_2 0x00000060UL +#define PDMA_BURST_1 0x00000070UL + +#define PDMA_DSCT_CTL_TXTYPE_Pos (2) +#define PDMA_DSCT_CTL_TXTYPE_Msk (0x1ul << PDMA_DSCT_CTL_TXTYPE_Pos) +#define PDMA_REQ_SINGLE 0x00000004UL +#define PDMA_REQ_BURST 0x00000000UL + +#define PDMA_DSCT_CTL_OPMODE_Pos (0) +#define PDMA_DSCT_CTL_OPMODE_Msk (0x3ul << PDMA_DSCT_CTL_OPMODE_Pos) +#define PDMA_OP_STOP 0x00000000UL +#define PDMA_OP_BASIC 0x00000001UL +#define PDMA_OP_SCATTER 0x00000002UL + +#define PDMA_DSCT_ENDSA_ENDSA_Pos (0) +#define PDMA_DSCT_ENDSA_ENDSA_Msk (0xfffffffful << PDMA_DSCT_ENDSA_ENDSA_Pos) + +#define PDMA_DSCT_ENDDA_ENDDA_Pos (0) +#define PDMA_DSCT_ENDDA_ENDDA_Msk (0xfffffffful << PDMA_DSCT_ENDDA_ENDDA_Pos) + +#define PDMA_DSCT_NEXT_NEXT_Pos (2) +#define PDMA_DSCT_NEXT_NEXT_Msk (0x3ffful << PDMA_DSCT_NEXT_NEXT_Pos) + +#define PDMA_CHCTL_CHEN_Pos (0) +#define PDMA_CHCTL_CHEN_Msk (0xfffful << PDMA_CHCTL_CHEN_Pos) + +#define PDMA_STOP_STOP_Pos (0) +#define PDMA_STOP_STOP_Msk (0xfffful << PDMA_STOP_STOP_Pos) + +#define PDMA_SWREQ_SWREQ_Pos (0) +#define PDMA_SWREQ_SWREQ_Msk (0xffful << PDMA_SWREQ_SWREQ_Pos) + +#define PDMA_TRGSTS_REQSTS_Pos (0) +#define PDMA_TRGSTS_REQSTS_Msk (0xfffful << PDMA_TRGSTS_REQSTS_Pos) + +#define PDMA_PRISET_FPRISET_Pos (0) +#define PDMA_PRISET_FPRISET_Msk (0xfffful << PDMA_PRISET_FPRISET_Pos) + +#define PDMA_PRICLR_FPRICLR_Pos (0) +#define PDMA_PRICLR_FPRICLR_Msk (0xfffful << PDMA_PRICLR_FPRICLR_Pos) + +#define PDMA_INTEN_INTEN_Pos (0) +#define PDMA_INTEN_INTEN_Msk (0xfffful << PDMA_INTEN_INTEN_Pos) + +#define PDMA_INTSTS_REQTOFX_Pos (8) +#define PDMA_INTSTS_REQTOFX_Msk (0xfffful << PDMA_INTSTS_REQTOFX_Pos) + +#define PDMA_INTSTS_TEIF_Pos (2) +#define PDMA_INTSTS_TEIF_Msk (0x1ul << PDMA_INTSTS_TEIF_Pos) + +#define PDMA_INTSTS_TDIF_Pos (1) +#define PDMA_INTSTS_TDIF_Msk (0x1ul << PDMA_INTSTS_TDIF_Pos) + +#define PDMA_INTSTS_ABTIF_Pos (0) +#define PDMA_INTSTS_ABTIF_Msk (0x1ul << PDMA_INTSTS_ABTIF_Pos) + +#define PDMA_ABTSTS_ABTIF_Pos (0) +#define PDMA_ABTSTS_ABTIF_Msk (0xfffful << PDMA_ABTSTS_ABTIF_Pos) + +#define PDMA_TDSTS_TDIF_Pos (0) +#define PDMA_TDSTS_TDIF_Msk (0xfffful << PDMA_TDSTS_TDIF_Pos) + +#define PDMA_SCATSTS_TEMPTYF_Pos (0) +#define PDMA_SCATSTS_TEMPTYF_Msk (0xfffful << PDMA_SCATSTS_TEMPTYF_Pos) + +#define PDMA_TACTSTS_TXACTF_Pos (0) +#define PDMA_TACTSTS_TXACTF_Msk (0xfffful << PDMA_TACTSTS_TXACTF_Pos) + +#define PDMA_SCATBA_SCATBA_Pos (16) +#define PDMA_SCATBA_SCATBA_Msk (0xfffful << PDMA_SCATBA_SCATBA_Pos) + +#define PDMA_TOC0_1_TOC1_Pos (16) +#define PDMA_TOC0_1_TOC1_Msk (0xfffful << PDMA_TOC0_1_TOC1_Pos) + +#define PDMA_TOC0_1_TOC0_Pos (0) +#define PDMA_TOC0_1_TOC0_Msk (0xfffful << PDMA_TOC0_1_TOC0_Pos) + +#define PDMA_TOC2_3_TOC3_Pos (16) +#define PDMA_TOC2_3_TOC3_Msk (0xfffful << PDMA_TOC2_3_TOC3_Pos) + +#define PDMA_TOC2_3_TOC2_Pos (0) +#define PDMA_TOC2_3_TOC2_Msk (0xfffful << PDMA_TOC2_3_TOC2_Pos) + +#define PDMA_TOC4_5_TOC5_Pos (16) +#define PDMA_TOC4_5_TOC5_Msk (0xfffful << PDMA_TOC4_5_TOC5_Pos) + +#define PDMA_TOC4_5_TOC4_Pos (0) +#define PDMA_TOC4_5_TOC4_Msk (0xfffful << PDMA_TOC4_5_TOC4_Pos) + +#define PDMA_TOC6_7_TOC7_Pos (16) +#define PDMA_TOC6_7_TOC7_Msk (0xfffful << PDMA_TOC6_7_TOC7_Pos) + +#define PDMA_TOC6_7_TOC6_Pos (0) +#define PDMA_TOC6_7_TOC6_Msk (0xfffful << PDMA_TOC6_7_TOC6_Pos) + +#define PDMA_TOC8_9_TOC9_Pos (16) +#define PDMA_TOC8_9_TOC9_Msk (0xfffful << PDMA_TOC8_9_TOC9_Pos) + +#define PDMA_TOC8_9_TOC8_Pos (0) +#define PDMA_TOC8_9_TOC8_Msk (0xfffful << PDMA_TOC8_9_TOC8_Pos) + +#define PDMA_TOC10_11_TOC11_Pos (16) +#define PDMA_TOC10_11_TOC11_Msk (0xfffful << PDMA_TOC10_11_TOC11_Pos) + +#define PDMA_TOC10_11_TOC10_Pos (0) +#define PDMA_TOC10_11_TOC10_Msk (0xfffful << PDMA_TOC10_11_TOC10_Pos) + +#define PDMA_TOC12_13_TOC13_Pos (16) +#define PDMA_TOC12_13_TOC13_Msk (0xfffful << PDMA_TOC12_13_TOC13_Pos) + +#define PDMA_TOC12_13_TOC12_Pos (0) +#define PDMA_TOC12_13_TOC12_Msk (0xfffful << PDMA_TOC12_13_TOC12_Pos) + +#define PDMA_TOC14_15_TOC15_Pos (16) +#define PDMA_TOC14_15_TOC15_Msk (0xfffful << PDMA_TOC14_15_TOC15_Pos) + +#define PDMA_TOC14_15_TOC14_Pos (0) +#define PDMA_TOC14_15_TOC14_Msk (0xfffful << PDMA_TOC14_15_TOC14_Pos) + +#define PDMA_REQSEL0_3_REQSRC3_Pos (24) +#define PDMA_REQSEL0_3_REQSRC3_Msk (0x1ful << PDMA_REQSEL0_3_REQSRC3_Pos) + +#define PDMA_REQSEL0_3_REQSRC2_Pos (16) +#define PDMA_REQSEL0_3_REQSRC2_Msk (0x1ful << PDMA_REQSEL0_3_REQSRC2_Pos) + +#define PDMA_REQSEL0_3_REQSRC1_Pos (8) +#define PDMA_REQSEL0_3_REQSRC1_Msk (0x1ful << PDMA_REQSEL0_3_REQSRC1_Pos) + +#define PDMA_REQSEL0_3_REQSRC0_Pos (0) +#define PDMA_REQSEL0_3_REQSRC0_Msk (0x1ful << PDMA_REQSEL0_3_REQSRC0_Pos) + +#define PDMA_REQSEL4_7_REQSRC7_Pos (24) +#define PDMA_REQSEL4_7_REQSRC7_Msk (0x1ful << PDMA_REQSEL4_7_REQSRC7_Pos) + +#define PDMA_REQSEL4_7_REQSRC6_Pos (16) +#define PDMA_REQSEL4_7_REQSRC6_Msk (0x1ful << PDMA_REQSEL4_7_REQSRC6_Pos) + +#define PDMA_REQSEL4_7_REQSRC5_Pos (8) +#define PDMA_REQSEL4_7_REQSRC5_Msk (0x1ful << PDMA_REQSEL4_7_REQSRC5_Pos) + +#define PDMA_REQSEL4_7_REQSRC4_Pos (0) +#define PDMA_REQSEL4_7_REQSRC4_Msk (0x1ful << PDMA_REQSEL4_7_REQSRC4_Pos) + +#define PDMA_REQSEL8_11_REQSRC11_Pos (24) +#define PDMA_REQSEL8_11_REQSRC11_Msk (0x1ful << PDMA_REQSEL8_11_REQSRC11_Pos) + +#define PDMA_REQSEL8_11_REQSRC10_Pos (16) +#define PDMA_REQSEL8_11_REQSRC10_Msk (0x1ful << PDMA_REQSEL8_11_REQSRC10_Pos) + +#define PDMA_REQSEL8_11_REQSRC9_Pos (8) +#define PDMA_REQSEL8_11_REQSRC9_Msk (0x1ful << PDMA_REQSEL8_11_REQSRC9_Pos) + +#define PDMA_REQSEL8_11_REQSRC8_Pos (0) +#define PDMA_REQSEL8_11_REQSRC8_Msk (0x1ful << PDMA_REQSEL8_11_REQSRC8_Pos) + +#define PDMA_REQSEL12_15_REQSRC15_Pos (24) +#define PDMA_REQSEL12_15_REQSRC15_Msk (0x1ful << PDMA_REQSEL12_15_REQSRC15_Pos) + +#define PDMA_REQSEL12_15_REQSRC14_Pos (16) +#define PDMA_REQSEL12_15_REQSRC14_Msk (0x1ful << PDMA_REQSEL12_15_REQSRC14_Pos) + +#define PDMA_REQSEL12_15_REQSRC13_Pos (8) +#define PDMA_REQSEL12_15_REQSRC13_Msk (0x1ful << PDMA_REQSEL12_15_REQSRC13_Pos) + +#define PDMA_REQSEL12_15_REQSRC12_Pos (0) +#define PDMA_REQSEL12_15_REQSRC12_Msk (0x1ful << PDMA_REQSEL12_15_REQSRC12_Pos) + +/* PDMA Channel Select */ +#define PDMA_I3C1_RX 5 +#define PDMA_I3C1_TX 6 +#define PDMA_I3C2_RX 7 +#define PDMA_I3C2_TX 8 +#define PDMA_I3C3_RX 9 +#define PDMA_I3C3_TX 10 +#define PDMA_I3C4_RX 11 +#define PDMA_I3C4_TX 12 +#define PDMA_I3C5_RX 13 +#define PDMA_I3C5_TX 14 +#define PDMA_I3C6_RX 15 +#define PDMA_I3C6_TX 16 + +#define PDMA_OFFSET 0 +#define PDMA_CH_MAX 16 + +#ifdef __cplusplus +extern "C" + { +#endif + +#ifdef __cplusplus + } +#endif + +#endif /* _I3C_H */ diff --git a/include/drivers/i3c/NPCM4XX/i3c_master.h b/include/drivers/i3c/NPCM4XX/i3c_master.h new file mode 100644 index 00000000000000..883736b4fbd848 --- /dev/null +++ b/include/drivers/i3c/NPCM4XX/i3c_master.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef __I3C_MASTER_H__ +#define __I3C_MASTER_H__ + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +extern __u32 I3C_Master_Callback(__u32 TaskInfo, __u32 ErrDetail); + +extern __u32 I3C_DO_NACK(I3C_TASK_INFO_t *pTaskInfo); +extern __u32 I3C_DO_WRABT(I3C_TASK_INFO_t *pTaskInfo); +extern __u32 I3C_DO_SLVSTART(I3C_TASK_INFO_t *pTaskInfo); +extern __u32 I3C_DO_SW_TIMEOUT(I3C_TASK_INFO_t *pTaskInfo); + +extern __u32 I3C_DO_IBI(I3C_TASK_INFO_t *pTaskInfo); +extern __u32 I3C_DO_HOT_JOIN(I3C_TASK_INFO_t *pTaskInfo); +extern __u32 I3C_DO_MASTER_REQUEST(I3C_TASK_INFO_t *pTaskInfo); + +extern __u32 I3C_DO_ENEC(I3C_TASK_INFO_t *pTaskInfo); +extern __u32 I3C_DO_DISEC(I3C_TASK_INFO_t *pTaskInfo); +extern __u32 I3C_DO_RSTDAA(I3C_TASK_INFO_t *pTaskInfo); +extern __u32 I3C_DO_ENTDAA(I3C_TASK_INFO_t *pTaskInfo); +extern __u32 I3C_DO_SETAASA(I3C_TASK_INFO_t *pTaskInfo); +extern __u32 I3C_DO_SETHID(I3C_TASK_INFO_t *pTaskInfo); +extern __u32 I3C_DO_SETDASA(I3C_TASK_INFO_t *pTaskInfo); +extern __u32 I3C_DO_SETNEWDA(I3C_TASK_INFO_t *pTaskInfo); + +/* Operation */ +extern void I3C_Master_Start_Request(__u32 Parm); +extern void I3C_Master_Stop_Request(__u32 Parm); +extern void I3C_Master_End_Request(__u32 Parm); +extern void I3C_Master_Run_Next_Frame(__u32 Parm); +extern void I3C_Master_New_Request(__u32 Parm); +extern void I3C_Master_Insert_DISEC_After_IbiNack(__u32 Parm); +extern void I3C_Master_IBIACK(__u32 Parm); +extern void I3C_Master_Insert_GETACCMST_After_IbiAckMR(__u32 Parm); +extern void I3C_Master_Insert_ENTDAA_After_IbiAckHJ(__u32 Parm); + +/* PDMA */ +extern I3C_ErrCode_Enum Setup_Master_Write_DMA(I3C_DEVICE_INFO_t *pDevice); +extern I3C_ErrCode_Enum Setup_Master_Read_DMA(I3C_DEVICE_INFO_t *pDevice); + +#ifdef __cplusplus +} +#endif + +#endif /* __I3C_MASTER_H__ */ diff --git a/include/drivers/i3c/NPCM4XX/i3c_slave.h b/include/drivers/i3c/NPCM4XX/i3c_slave.h new file mode 100644 index 00000000000000..9dd7950da7c966 --- /dev/null +++ b/include/drivers/i3c/NPCM4XX/i3c_slave.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef __I3C_SLAVE_H__ +#define __I3C_SLAVE_H__ + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +extern __u32 I3C_Slave_Callback(__u32 TaskInfo, __u32 ErrDetail); + +/* response */ +extern __u32 I3C_DO_NACK_SLVSTART(I3C_TASK_INFO_t *pTaskInfo); + +/* Operation */ +extern void I3C_Slave_Start_Request(__u32 Parm); +extern void I3C_Slave_End_Request(__u32 Parm); + +extern I3C_ErrCode_Enum I3C_Slave_Prepare_Response(I3C_DEVICE_INFO_t *pDevice, + __u16 wrLen, __u8 *pWrBuf); +extern I3C_ErrCode_Enum I3C_Slave_Update_Pending(I3C_DEVICE_INFO_t *pDevice, __u8 mask); +extern I3C_ErrCode_Enum I3C_Slave_Finish_Response(I3C_DEVICE_INFO_t *pDevice); +extern I3C_ErrCode_Enum I3C_Slave_Check_Response_Complete(I3C_DEVICE_INFO_t *pDevice); +extern I3C_ErrCode_Enum I3C_Slave_Check_IBIDIS(I3C_DEVICE_INFO_t *pDevice, _Bool *bRet); + +/* PDMA */ +extern I3C_ErrCode_Enum Setup_Slave_Write_DMA(I3C_DEVICE_INFO_t *pDevice); +extern I3C_ErrCode_Enum Setup_Slave_Read_DMA(I3C_DEVICE_INFO_t *pDevice); +extern I3C_ErrCode_Enum Setup_Slave_IBI_DMA(I3C_DEVICE_INFO_t *pDevice); + +extern void I3C_Update_Dynamic_Address(__u32 Parm); +extern void I3C_Prepare_To_Read_Command(__u32 Parm); +extern uint8_t GetCmdWidth(uint8_t width_type); + +#ifdef __cplusplus +} +#endif + +#endif /* __I3C_SLAVE_H__ */ diff --git a/include/drivers/i3c/NPCM4XX/pub_I3C.h b/include/drivers/i3c/NPCM4XX/pub_I3C.h new file mode 100644 index 00000000000000..e6139e47a94a6a --- /dev/null +++ b/include/drivers/i3c/NPCM4XX/pub_I3C.h @@ -0,0 +1,681 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef EXPORTS_PUB_I3C_H_ +#define EXPORTS_PUB_I3C_H_ + +#include +#include +#include +#include + +#include +#include + +/* generic data type used in lib source for compatibility */ +typedef uint8_t __u8; +typedef uint16_t __u16; +typedef uint32_t __u32; +typedef int8_t __s8; +typedef int16_t __s16; +typedef int32_t __s32; + +/*typedef struct i3c_reg I3C_T;*/ +#define I3C_T struct i3c_reg + +#define FALSE false +#define TRUE true + +#define LSByte(word) ((__u8)((word) & 0xFF)) +#define LSHalf(word) ((__u16)((word) & 0xFFFF)) +#define MSByte(word) ((__u8)((word) >> 24)) +#define MSHalf(word) ((__u16)((word) >> 16)) + +#ifndef MaskBit +#define MaskBit(x) ((__u32) 0x1 << (x)) +#endif + +#ifndef make32 +#define make32(whi, wlo) ((__u32)(((__u16)(wlo)) | (((__u32)(whi)) << 16))) +#endif + +#ifndef make16 +#define make16(bhi, blo) ((__u16)(((__u8)(blo)) | (((__u16)(bhi)) << 8))) +#endif + +#ifndef BIT +#define BIT(b) (1 << (b)) +#endif + +#ifndef IS_BIT_SET +#define IS_BIT_SET(reg, bit) (((reg >> bit) & (0x1)) != 0) +#endif + + +/*----------------------------- I3C --------------------------------*/ +#define I3C_TRANSFER_SPEED_SDR_12p5MHZ 12500000 +#define I3C_TRANSFER_SPEED_SDR_8MHZ 8000000 +#define I3C_TRANSFER_SPEED_SDR_6MHZ 6000000 +#define I3C_TRANSFER_SPEED_SDR_4MHZ 4000000 +#define I3C_TRANSFER_SPEED_SDR_2MHZ 2000000 +#define I3C_TRANSFER_SPEED_SDR_1MHZ 1000000 + +#define I3C_TRANSFER_SPEED_SDR_IBI 1000000 + +#define I3C_TRANSFER_SPEED_I2C_1MHZ 1000000 +#define I3C_TRANSFER_SPEED_I2C_400KHZ 400000 +#define I3C_TRANSFER_SPEED_I2C_100KHZ 100000 + +#define I3C_TRANSFER_SPEED_UNDEF 0 + +#define I3C_PAYLOAD_SIZE_MAX 69 +#define IBI_PAYLOAD_SIZE_MAX 8 + +enum I3C_PORT { + I3C1_IF, + I3C2_IF, + I3C3_IF, + I3C4_IF, + I3C5_IF, + I3C6_IF, +#if (CHIP_ID_NPCM4XX == 5832) + I3C_PORT_MAX = 2, +#else + I3C_PORT_MAX = 6, +#endif +}; + +#define I3C_PORT_Enum enum I3C_PORT + +#define I3C_BUS_COUNT_MAX I3C_PORT_MAX + +#define I2C_STATIC_ADDR_DEFAULT_7BIT 0xFFU +#define I3C_DYNAMIC_ADDR_DEFAULT_7BIT 0x00U + +/*#define I3C_BROADCAST_ADDR 0x7E*/ + +enum I3C_DEVICE_TYPE { + I3C_DEVICE_TYPE_PURE_I3C = 0U, + I3C_DEVICE_TYPE_PURE_I2C = 1U, + I3C_DEVICE_TYPE_MIXED = 2U, +}; + +#define I3C_DEVICE_TYPE_Enum enum I3C_DEVICE_TYPE + +enum I3C_DEVICE_MODE { + I3C_DEVICE_MODE_DISABLE = 0U, + I3C_DEVICE_MODE_CURRENT_MASTER = 1U, + I3C_DEVICE_MODE_SLAVE_ONLY = 2U, + I3C_DEVICE_MODE_SECONDARY_MASTER = 3U, +}; + +#define I3C_DEVICE_MODE_Enum enum I3C_DEVICE_MODE + +enum I3C_SLAVE_DEVICE_MODE { + I3C_SLAVE_DEVICE_MODE_I2C, + I3C_SLAVE_DEVICE_MODE_I3C, +}; + +#define I3C_SLAVE_DEVICE_MODE_Enum enum I3C_SLAVE_DEVICE_MODE + +enum I3C_BUS_STATE { + I3C_BUS_STATE_DEFAULT, + I3C_BUS_STATE_WAIT_RESET_DONE, + I3C_BUS_STATE_WAIT_CLEAR_DONE, + I3C_BUS_STATE_INIT, + I3C_BUS_STATE_IDLE, +}; + +#define I3C_BUS_STATE_Enum enum I3C_BUS_STATE + +enum I3C_BUS_TYPE { + I3C_BUS_TYPE_PURE_I3C = 0U, + I3C_BUS_TYPE_PURE_I2C = 1U, + I3C_BUS_TYPE_MIXED = 2U, +}; + +#define I3C_BUS_TYPE_Enum enum I3C_BUS_TYPE + +enum I3C_VERSION { + I3C_VER_1p0 = 0U, + I3C_VER_1p1 = 1U, +}; + +#define I3C_VERSION_Enum enum I3C_VERSION + +struct I3C_BAUDRATE { + __u32 i3cI2c; + __u32 i3cSdr; + + __u16 tHmax; + __u16 tHmin; + __u16 tLmax; + __u16 tLmin; + __u16 tTimeout; + _Bool bRunI3C; +}; + +#define I3C_BAUDRATE_t struct I3C_BAUDRATE + +struct I3C_DEVICE_INFO; +struct I3C_DEVICE_INFO_SHORT; + +/*typedef */struct I3C_BUS_INFO { + __u8 busno; + + I3C_BUS_TYPE_Enum busType; + I3C_VERSION_Enum busVersion; + I3C_BUS_STATE_Enum busState; + struct I3C_TRANSFER_TASK *pCurrentTask; + __u16 timer_ms; + + __u8 DevCount; + struct I3C_DEVICE_INFO_SHORT *pDevList; + struct I3C_DEVICE_INFO *pCurrentMaster; +} /* I3C_BUS_INFO_t*/; + +#define I3C_BUS_INFO_t struct I3C_BUS_INFO + +/*typedef */union I3C_DEVICE_ATTRIB_t { + struct { + __u16 reqSETAASA : 1; + __u16 reqSETDASA : 1; + __u16 reqRSTDAA : 1; + __u16 reqSETHID : 1; + __u16 reqHotJoin : 1; + __u16 reqPostInit : 1; + + __u16 doneSETAASA : 1; + __u16 doneSETDASA : 1; + __u16 doneRSTDAA : 1; + __u16 doneSETHID : 1; + __u16 doneHotJoin : 1; + __u16 donePostInit : 1; + + __u16 suppMST : 1; + __u16 suppSLV : 1; + __u16 defaultMST : 1; + + __u16 suppENTDAA : 1; + __u16 present: 1; + __u16 runI3C: 1; + } b; + __u16 U16; +} /* I3C_DEVICE_ATTRIB_t */; + +#define I3C_DEVICE_ATTRIB_t union I3C_DEVICE_ATTRIB_t + +/*typedef */struct I3C_DEVICE_INFO_SHORT { + __u8 staticAddr; + __u8 dynamicAddr; + __u8 pid[6]; + __u8 bcr; + __u8 dcr; + + I3C_DEVICE_ATTRIB_t attr; + struct I3C_DEVICE_INFO_SHORT *pNextDev; + void *pDeviceInfo; +} /* I3C_DEVICE_INFO_SHORT_t */; + +#define I3C_DEVICE_INFO_SHORT_t struct I3C_DEVICE_INFO_SHORT + +#define CMD_INVALID_SDR 0xFE +#define CMD_INVALID_DDRRd 0xFE +#define CMD_DEFAULT 0xFD +#define CMD_INVALID 0xFE +#define CMD_INVALID_DDRWr 0x7E + +#define TIMEOUT_TYPICAL 10 + +#define NOT_HIF FALSE +#define IS_HIF TRUE + +/*typedef */union cmd_t { + __u8 cmd8; + __u16 cmd16; +} /* cmd_t*/; + +#define cmd_t union cmd_t + +/*typedef */struct cmd_attrib { + __u8 endian : 1; /* 0b: little, 1b: bigh endian, if width != 0 */ + __u8 width : 1; /* 0b = 1, 1b = 2 */ + __u8 write : 1; + __u8 read : 1; +} /* cmd_attrib_t */; + +#define cmd_attrib_t struct cmd_attrib + +/*typedef */struct I3C_REG_ITEM { + cmd_t cmd; + + union { + __u8 rw; + cmd_attrib_t attr; + }; + + __u16 len; + __u8 *buf; +} /* I3C_REG_ITEM_t*/; + +#define I3C_REG_ITEM_t struct I3C_REG_ITEM + +enum I3C_ErrCode { + I3C_ERR_OK = 0, + I3C_ERR_PENDING = 1, /* wait i3c engine to process it */ + I3C_ERR_OUT_OF_MEMORY = 2, /* allocate memory fail */ + I3C_ERR_PARAMETER_INVALID = 4, /* parameter invalid */ + I3C_ERR_TASK_INVALID = 8, /* illegal task */ + I3C_ERR_MEMORY_RAN_OUT = 16, /* allocate memory is insufficient */ + I3C_ERR_DATA_ERROR = 32, /* crc error for SPD5118, MCTP */ + I3C_ERR_SW_TIMEOUT = 64, /* timer timeout, or retry too many times */ + I3C_ERR_HW_NOT_SUPPORT, + I3C_ERR_BUS_ERROR, + I3C_ERR_MERRWARN, + I3C_ERR_NACK, + I3C_ERR_TERM, + I3C_ERR_WRABT, + I3C_ERR_ERRWARN, + I3C_ERR_HW_TIMEOUT, + I3C_ERR_BUS_BUSY, + I3C_ERR_SLVSTART, + I3C_ERR_IBI, + I3C_ERR_MR, + I3C_ERR_HJ, + I3C_ERR_NACK_SLVSTART, +}; + +#define I3C_ErrCode_Enum enum I3C_ErrCode + +enum I3C_CCC { + CCC_BROADCAST_ENEC = 0x00, /* Enable Events Command */ + CCC_BROADCAST_DISEC = 0x01, /* Disable Events Command */ + CCC_BROADCAST_ENTAS0 = 0x02, /* Enter Activity State 0, 1 us */ + CCC_BROADCAST_ENTAS1 = 0x03, /* Enter Activity State 1, 100 us */ + CCC_BROADCAST_ENTAS2 = 0x04, /* Enter Activity State 2, 2 ms */ + CCC_BROADCAST_ENTAS3 = 0x05, /* Enter Activity State 3, 50 ms */ + CCC_BROADCAST_RSTDAA = 0x06, /* Reset Dynamic Address Assignment */ + CCC_BROADCAST_ENTDAA = 0x07, /* Enter Dynamic Address Assignment */ + CCC_BROADCAST_DEFSLVS = 0x08, + CCC_BROADCAST_SETMWL = 0x09, + CCC_BROADCAST_SETMRL = 0x0A, + CCC_BROADCAST_ENTTM = 0x0B, + CCC_BROADCAST_SETBUSCON = 0x0C, +/* CCC_BROADCAST_rsvd = 0x0D - 0x11, */ + CCC_BROADCAST_ENDXFER = 0x12, +/* CCC_BROADCAST_rsvd = 0x13 - 0x1F, */ + CCC_BROADCAST_ENTHDR0 = 0x20, + CCC_BROADCAST_ENTHDR1 = 0x21, + CCC_BROADCAST_ENTHDR2 = 0x22, + CCC_BROADCAST_ENTHDR3 = 0x23, + CCC_BROADCAST_ENTHDR4 = 0x24, + CCC_BROADCAST_ENTHDR5 = 0x25, + CCC_BROADCAST_ENTHDR6 = 0x26, + CCC_BROADCAST_ENTHDR7 = 0x27, + CCC_BROADCAST_SETXTIME = 0x28, + CCC_BROADCAST_SETAASA = 0x29, /* Set All Addresses to Static Addresses */ + CCC_BROADCAST_RSTACT = 0x2A, + CCC_BROADCAST_DEFGRPA = 0x2B, + CCC_BROADCAST_RSTGRPA = 0x2C, + CCC_BROADCAST_MLANE = 0x2D, +/* CCC_BROADCAST_rsvd = 0x2E - 0x48, */ +/* CCC_BROADCAST_rsvd = 0x49 - 0x4C, */ +/* CCC_BROADCAST_rsvd = 0x4D - 0x57, */ +/* CCC_BROADCAST_rsvd = 0x58 - 0x5B, */ +/* CCC_BROADCAST_rsvd = 0x5C - 0x60, */ +/* CCC_BROADCAST_rsvd = 0x61 - 0x7F, */ + CCC_BROADCAST_SETHID = 0x61, /* JEDEC DDR5 */ + CCC_BROADCAST_DEVCTRL = 0x62, /* JEDEC DDR5 */ + CCC_DIRECT_ENEC = 0x80, /* Enable Events Command, Direct Set */ + CCC_DIRECT_DISEC = 0x81, /* Disable Events Command, Direct Set */ + CCC_DIRECT_ENTAS0 = 0x82, /* Enter Activity State 0, 1 us, Direct Set */ + CCC_DIRECT_ENTAS1 = 0x83, /* Enter Activity State 1, 100 us, Direct Set */ + CCC_DIRECT_ENTAS2 = 0x84, /* Enter Activity State 2, 2 ms, Direct Set */ + CCC_DIRECT_ENTAS3 = 0x85, /* Enter Activity State 3, 50 ms, Direct Set */ + CCC_DIRECT_RSTDAA = 0x86, /* Reset Dynamic Address Assignment, Direct Set */ + CCC_DIRECT_SETDASA = 0x87, /* Set Dynamic Address from Static Address, Direct Set */ + CCC_DIRECT_SETNEWDA = 0x88, /* Set New Dynamic Address, Direct Set */ + CCC_DIRECT_SETMWL = 0x89, /* Set Max Write Length, Direct Set */ + CCC_DIRECT_SETMRL = 0x8A, /* Set Max Read Length, Direct Set */ + CCC_DIRECT_GETMWL = 0x8B, /* Get Max Write Length, Direct Get */ + CCC_DIRECT_GETMRL = 0x8C, /* Get Max Read Length, Direct Get */ + CCC_DIRECT_GETPID = 0x8D, /* Get Provisioned ID, Direct Get */ + CCC_DIRECT_GETBCR = 0x8E, /* Get Bus Characteristics Register, Direct Get */ + CCC_DIRECT_GETDCR = 0x8F, /* Get Device Characteristics Register, Direct Get */ + CCC_DIRECT_GETSTATUS = 0x90, /* Get Device Status, Direct Get */ + CCC_DIRECT_GETACCMST = 0x91, + CCC_DIRECT_GETACCCR = 0x91, /* Get Accept Controller Role, Direct Get */ + CCC_DIRECT_ENDXFER = 0x92, /* Data Transfer Ending Procedure Control, Direct Set */ + CCC_DIRECT_SETBRGTGT = 0x93, /* Set Bridge Targets, Direct Set */ + CCC_DIRECT_GETMXDS = 0x94, /* Get Max Data Speed, Direct Get */ + CCC_DIRECT_GETCAPS = 0x95, /* GetOptional Feature Capabilities, Direct Get */ + CCC_DIRECT_SETROUTE = 0x96, /* Set Route, Direct Set */ +/* CCC_DIRECT_D2DXFER = 0x97, // Device to Device Tuneling Control, not include in Basic*/ + CCC_DIRECT_SETXTIME = 0x98, /* Set Exchange Timing Information, Direct Set */ + CCC_DIRECT_GETXTIME = 0x99, /* Get Exchange Timing Information, Direct Get */ + CCC_DIRECT_RSTACT = 0x9A, /* Target Reset Action, Direct Set */ + CCC_DIRECT_SETGRPA = 0x9B, /* Set Group Address */ + CCC_DIRECT_RSTGRPA = 0x9C, /* Reset Group Address */ + CCC_DIRECT_MLANE = 0x9D, +/* CCC_DIRECT_rsvd = 0x9E - 0xBF, */ +/* CCC_DIRECT_rsvd = 0xC0 - 0xC3, */ +/* CCC_DIRECT_rsvd = 0xC4 - 0xD6, */ +/* CCC_DIRECT_rsvd = 0xD7 - 0xDA, */ +/* CCC_DIRECT_rsvd = 0xDB - 0xDF, */ +/* CCC_DIRECT_rsvd = 0xE0 - 0xFE, */ +/* CCC_DIRECT_rsvd = 0xFF, */ +}; + +#define I3C_CCC_Enum enum I3C_CCC + +#define ENEC_MASK_ENINT (0x01) +#define ENEC_MASK_ENMR (0x02) +#define ENEC_MASK_ENHJ (0x08) + +#define DISEC_MASK_ENINT (0x01) +#define DISEC_MASK_ENMR (0x02) +#define DISEC_MASK_ENHJ (0x08) + +enum I3C_TRANSFER_PROTOCOL { + I3C_TRANSFER_PROTOCOL_I2C_WRITE = 0x00, + I3C_TRANSFER_PROTOCOL_I2C_READ = 0x01, + I3C_TRANSFER_PROTOCOL_I2C_WRITEnREAD = 0x02, + + I3C_TRANSFER_PROTOCOL_I3C_WRITE = 0x10, + I3C_TRANSFER_PROTOCOL_I3C_READ = 0x11, + I3C_TRANSFER_PROTOCOL_I3C_WRITEnREAD = 0x12, + I3C_TRANSFER_PROTOCOL_I3C_W7E = 0x13, + I3C_TRANSFER_PROTOCOL_I3C_R7E = 0x14, + I3C_TRANSFER_PROTOCOL_I3C_W7EnREAD = 0x15, + + I3C_TRANSFER_PROTOCOL_DDR_WRITE = 0x20, + I3C_TRANSFER_PROTOCOL_DDR_READ = 0x21, + + I3C_TRANSFER_PROTOCOL_CCCb = 0x40U, /* Broadcast CCC*/ + I3C_TRANSFER_PROTOCOL_CCCw = 0x41U, /* Direct Write*/ + I3C_TRANSFER_PROTOCOL_CCCr = 0x42U, /* Direct Read*/ + I3C_TRANSFER_PROTOCOL_ENTDAA = 0x43U, /* ENTDAA*/ + + I3C_TRANSFER_PROTOCOL_EVENT = 0x80U, /* for IBI/Hot-Join/Master Request*/ + I3C_TRANSFER_PROTOCOL_IBI = 0x81U, /* Slave's task for IBI*/ + I3C_TRANSFER_PROTOCOL_MASTER_REQUEST = 0x82U, /* Slave's task for Master Request*/ + I3C_TRANSFER_PROTOCOL_HOT_JOIN = 0x84U, /* Slave's task for Hot-Join*/ +}; + +#define I3C_TRANSFER_PROTOCOL_Enum enum I3C_TRANSFER_PROTOCOL + +#define I2C_TRANSFER_PROTOCOL(x) (((x & 0xF0) == 0x00) ? TRUE : FALSE) +#define I3C_TRANSFER_PROTOCOL(x) (((x & 0xF0) == 0x10) ? TRUE : FALSE) +#define DDR_TRANSFER_PROTOCOL(x) (((x & 0xF0) == 0x20) ? TRUE : FALSE) +#define CCC_TRANSFER_PROTOCOL(x) (((x & 0xF0) == 0x40) ? TRUE : FALSE) + #define CCC_BROADCAST(CCC) (((CCC >= 0) && (CCC <= 0x7F)) ? TRUE : FALSE) + #define CCC_DIRECT(CCC) (((CCC >= 0x80) && (CCC <= 0xFE)) ? TRUE : FALSE) +#define EVENT_TRANSFER_PROTOCOL(x) (((x & 0xF0) == 0x80) ? TRUE : FALSE) +#define SLAVE_TRANSFER_PROTOCOL(x) (((x == 0x81) || (x == 0x82) || (x == 0x84)) ? TRUE : FALSE) + +#define WRITE_TRANSFER_PROTOCOL(x) (((x & 0xCF) == 0x00) ? TRUE : FALSE) +#define READ_TRANSFER_PROTOCOL(x) (((x & 0xCF) == 0x01) ? TRUE : FALSE) +#define WRITEnREAD_TRANSFER_PROTOCOL(x) (((x & 0xCF) == 0x02) ? TRUE : FALSE) +#define W7E_TRANSFER_PROTOCOL(x) (((x & 0xCF) == 0x03) ? TRUE : FALSE) +#define R7E_TRANSFER_PROTOCOL(x) (((x & 0xCF) == 0x04) ? TRUE : FALSE) +#define W7EnREAD_TRANSFER_PROTOCOL(x) (((x & 0xCF) == 0x05) ? TRUE : FALSE) + +enum I3C_TASK_POLICY { + I3C_TASK_POLICY_INSERT_FIRST, + I3C_TASK_POLICY_APPEND_LAST, +}; + +#define I3C_TASK_POLICY_Enum enum I3C_TASK_POLICY + +enum I3C_TRANSFER_FLAG { + I3C_TRANSFER_NORMAL = 0x00U, + I3C_TRANSFER_NO_STOP = 0x01U, + I3C_TRANSFER_REPEAT_START = 0x02U, + I3C_TRANSFER_NO_START = 0x04U, + I3C_TRANSFER_RETRY_ENABLE = 0x08U, + I3C_TRANSFER_RETRY_WITHOUT_STOP = 0x10U, + I3C_TRANSFER_WORD_WIDTH = 0x20U, + I3C_TRANSFER_MESSAGE_MODE = 0x40U, + I3C_TRANSFER_NAK = 0x100U, +}; + +#define I3C_TRANSFER_FLAG_Enum enum I3C_TRANSFER_FLAG + +enum I3C_TRANSFER_DIR { + I3C_TRANSFER_DIR_WRITE = 0U, + I3C_TRANSFER_DIR_READ = 1U, +}; + +#define I3C_TRANSFER_DIR_Enum enum I3C_TRANSFER_DIR + +enum I3C_TRANSFER_TYPE { + I3C_TRANSFER_TYPE_SDR = 0U, + I3C_TRANSFER_TYPE_I2C = 1U, + I3C_TRANSFER_TYPE_DDR = 2U, +}; + +#define I3C_TRANSFER_TYPE_Enum enum I3C_TRANSFER_TYPE + +enum I3C_IBITYPE { + I3C_IBITYPE_None = 0, + I3C_IBITYPE_IBI = 1, + I3C_IBITYPE_MstReq = 2, + I3C_IBITYPE_HotJoin = 3, +}; + +#define I3C_IBITYPE_Enum enum I3C_IBITYPE + +typedef __u32 (*ptrI3C_RetFunc)(__u32 TaskInfo, __u32 ErrDetail); + +struct I3C_CAPABILITY_INFO { + __u8 MASTER : 1; + __u8 SLAVE : 1; + + __u8 INT : 1; + __u8 DMA : 1; + __u8 OFFLINE : 1; + + __u8 HDR_DDR : 1; + __u8 HDR_TSP : 1; + __u8 HDR_TSL : 1; + __u8 IBI : 1; + __u8 HOT_JOIN : 1; + __u8 MASTER_REQUEST : 1; + + /* Time Control */ + __u8 SYNC : 1; + __u8 ASYNC0 : 1; + __u8 ASYNC1 : 1; + __u8 ASYNC2 : 1; + __u8 ASYNC3 : 1; + + /* Version */ + __u8 I3C_VER_1p0 : 1; + __u8 I3C_VER_1p1 : 1; + + __u8 FIFO_TX_LEN; + __u8 FIFO_RX_LEN; +}; + +#define I3C_CAPABILITY_INFO_t struct I3C_CAPABILITY_INFO + +struct I3C_DEVICE_INFO { + struct I3C_CAPABILITY_INFO capability; + I3C_PORT_Enum port; + struct I3C_BUS_INFO *pOwner; /* bus */ + struct I3C_DEVICE_INFO_SHORT *pDevInfo; + + I3C_DEVICE_MODE_Enum mode; /* off, master on, slave only, master capable */ + _Bool bRunI3C; /* current slave device working mode, 0:i2c, 1:i3c */ + + /* common */ + __u8 dynamicAddr; + __u8 pid[6]; + __u8 dcr; /* Device characteristics register information.*/ + __u8 bcr; /* Bus characteristics register information.*/ + __u16 vendorID; /* Device vendor ID (manufacture ID).*/ + __u32 partNumber; /* Device part number info */ + + /* master config */ + _Bool enableOpenDrainHigh; + _Bool enableOpenDrainStop; + _Bool disableTimeout; + _Bool ackIBI; /* For master, used to define master should ack or nack the slave request */ + /* For slave, used to set correct protocol (with 7E)*/ + struct I3C_BAUDRATE baudrate; + + __u8 *pRxBuf; + __u8 *pTxBuf; + + __u16 rxOffset; + __u16 txOffset; + + __u16 rxLen; + __u16 txLen; + + /* slave config */ + __u8 staticAddr; /* 7-bit */ + _Bool stopSplitRead; /* 1b: master can read un-read data after STOP */ + /* 0b: slave should reset command, RX DMA/FIFO */ + __u8 cmdIndex; + I3C_REG_ITEM_t *pReg; + + _Bool bAbort; + volatile __u8 task_count; + struct I3C_TRANSFER_TASK *pTaskListHead; + ptrI3C_RetFunc callback; +}; + +#define I3C_DEVICE_INFO_t struct I3C_DEVICE_INFO + +/* + * initMode + * Used to configure how to init slave device on the bus + */ +#define INITMODE_I2C 0x0000U +#define INITMODE_I3C 0x0001U +#define INITMODE_BUSRESET 0x0002U +#define INITMODE_DEVCTRL 0x0004U +#define INITMODE_SETHID 0x0008U +#define INITMODE_SETAASA 0x0010U +#define INITMODE_SETDASA 0x0020U +#define INITMODE_ENTDAA 0x0040U +#define INITMODE_POWERON 0x0080U +#define INITMODE_POST_INIT 0x0100U +#define INITMODE_RSTDAA 0x0200U + +struct I3C_TASK_INFO { + struct I3C_TRANSFER_TASK *pTask; + I3C_ErrCode_Enum result; + ptrI3C_RetFunc callback; + + __u8 MasterRequest : 1; + __u8 bHIF : 1; + I3C_PORT_Enum Port; + + __u32 u32SwTimeout; + + void *pParentTaskInfo; + + /* used for Sensor module */ + __u8 idx; + __u8 fmt; +}; + +#define I3C_TASK_INFO_t struct I3C_TASK_INFO + +struct I3C_TRANSFER_TASK { + struct I3C_TASK_INFO *pTaskInfo; + + I3C_TRANSFER_PROTOCOL_Enum protocol; + __u32 baudrate; + __u8 address; + + __u8 *pWrBuf; + __u16 *pWrLen; + + __u8 *pRdBuf; + __u16 *pRdLen; + + struct I3C_TRANSFER_FRAME *pFrameList; + __u8 frame_count; + __u8 frame_idx; + + struct I3C_TRANSFER_TASK *pNextTask; +}; + +#define I3C_TRANSFER_TASK_t struct I3C_TRANSFER_TASK + +struct I3C_TRANSFER_FRAME { + struct I3C_TRANSFER_TASK *pOwner; + + I3C_TRANSFER_FLAG_Enum flag; + I3C_TRANSFER_TYPE_Enum type; + __u32 baudrate; + + __u8 address; + I3C_TRANSFER_DIR_Enum direction; + __u8 hdrcmd; + + __u16 access_len; + __u16 access_idx; + __u8 *access_buf; + __u8 retry_count; + + struct I3C_TRANSFER_FRAME *pNextFrame; +}; + +#define I3C_TRANSFER_FRAME_t struct I3C_TRANSFER_FRAME + +/* LSM6DSO */ +enum I3C_LSM6DSO_STATE { + I3C_LSM6DSO_STATE_DEFAULT, + I3C_LSM6DSO_STATE_INIT, + I3C_LSM6DSO_STATE_IDLE, + I3C_LSM6DSO_STATE_BUSY, + I3C_LSM6DSO_STATE_TASK_CANNOT_COMPLETE, + I3C_LSM6DSO_STATE_DEVICE_NOT_PRESENT, +}; + +#define I3C_LSM6DSO_STATE_Enum enum I3C_LSM6DSO_STATE + +enum LSM6DSO_POST_INIT_STATE { + LSM6DSO_POST_INIT_STATE_Default, + + LSM6DSO_POST_INIT_STATE_1, + LSM6DSO_POST_INIT_STATE_1_Wait, + LSM6DSO_POST_INIT_STATE_1_Done, + + LSM6DSO_POST_INIT_STATE_2, + LSM6DSO_POST_INIT_STATE_2_Wait, + LSM6DSO_POST_INIT_STATE_2_Done, + + LSM6DSO_POST_INIT_STATE_3, + LSM6DSO_POST_INIT_STATE_3_Wait, + LSM6DSO_POST_INIT_STATE_3_Done, + + LSM6DSO_POST_INIT_STATE_END, +}; + +#define LSM6DSO_POST_INIT_STATE_Enum enum LSM6DSO_POST_INIT_STATE + +struct LSM6DSO_DEVICE_INFO { + I3C_DEVICE_INFO_t i3c_device; + __u32 baudrate; + I3C_LSM6DSO_STATE_Enum state; + LSM6DSO_POST_INIT_STATE_Enum post_init_state; + __u16 initMode; + __u16 rxLen; + __u8 rxBuf[16]; + __u8 temp_val; +}; + +#define LSM6DSO_DEVICE_INFO_t struct LSM6DSO_DEVICE_INFO + +/* PENDINT definition */ +#define I3C_PENDING_NONE 0x00 +#define I3C_PENDING_MCTP 0x01 + +#endif /* EXPORTS_PUB_I3C_H_ */ diff --git a/include/drivers/i3c/i3c.h b/include/drivers/i3c/i3c.h new file mode 100644 index 00000000000000..a7da7c159a517a --- /dev/null +++ b/include/drivers/i3c/i3c.h @@ -0,0 +1,244 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +#define I3C_HOT_JOIN_ADDR 0x02 +#define I3C_BROADCAST_ADDR 0x7e +#define I3C_MAX_ADDR 0x7f + +#define I3C_CCC_DIRECT 0x80 + +/* broadcast / unicast commands */ +#define I3C_CCC_ENEC 0x00 +#define I3C_CCC_DISEC 0x01 +#define I3C_CCC_RSTDAA 0x06 +#define I3C_CCC_SETMWL 0x09 +#define I3C_CCC_SETMRL 0x0a + +/* broadcast only commands */ +#define I3C_CCC_ENTDAA 0x07 +#define I3C_CCC_SETAASA 0x29 +#define I3C_CCC_SETHID 0x61 +#define I3C_CCC_DEVCTRL 0x62 + +/* unicast only commands */ +#define I3C_CCC_SETDASA (0x7 | I3C_CCC_DIRECT) +#define I3C_CCC_GETMWL (0xb | I3C_CCC_DIRECT) +#define I3C_CCC_GETMRL (0xc | I3C_CCC_DIRECT) +#define I3C_CCC_GETPID (0xd | I3C_CCC_DIRECT) +#define I3C_CCC_GETBCR (0xe | I3C_CCC_DIRECT) +#define I3C_CCC_GETDCR (0xf | I3C_CCC_DIRECT) +#define I3C_CCC_GETSTATUS (0x10 | I3C_CCC_DIRECT) + +/* event id */ +#define I3C_CCC_EVT_SIR 0x1 +#define I3C_CCC_EVT_MR 0x2 +#define I3C_CCC_EVT_HJ 0x8 + +/** + * @brief I3C Common-Command-Codes (CCC) structure + * @param rnw 1'b0 = write command, 1'b1 = read command + * @param id command code + * @param addr address of slave device + * @param ret return value + * @param payload length: length of the payload. data: pointer to the payload + */ +struct i3c_ccc_cmd { + uint8_t rnw; + uint8_t id; + uint8_t addr; + uint8_t ret; + struct { + uint16_t length; + void *data; + } payload; +}; + +/** + * @brief I3C private transfer structure + * @param data pointer to the read/write data + * @param len length of the data + * @param rnw 1'b0 = write command, 1'b1 = read command + */ +struct i3c_priv_xfer { + union { + void *in; + void *out; + } data; + int len; + int rnw; +}; + +/* slave device structure */ +struct i3c_device_info { + uint64_t pid; + uint8_t dcr; + uint8_t bcr; + uint8_t static_addr; + uint8_t assigned_dynamic_addr; + uint8_t dynamic_addr; + uint32_t i2c_mode; +}; + +#define I3C_PID_VENDOR_ID(x) ((x) >> 33) +#define I3C_PID_VENDOR_ID_ASPEED 0x03f6 + +#define I3C_BCR_IBI_PAYLOAD BIT(2) + +/** + * @brief descriptor of the i3c device attached to the bus + * @param bus the bus controller which hosts the bus + * @param priv_data pointer to the low level driver private data + * @param info the device information + */ +struct i3c_dev_desc { + const struct device *bus; + struct i3c_device_info info; + void *priv_data; +}; + +/* MIPI I3C MDB definition: see https://www.mipi.org/MIPI_I3C_mandatory_data_byte_values_public */ +#define IBI_MDB_ID(grp, id) ((((grp) << 5) & GENMASK(7, 5)) | ((id) & GENMASK(4, 0))) +#define IBI_MDB_GET_GRP(m) (((m) & GENMASK(7, 5)) >> 5) +#define IBI_MDB_GET_ID(m) ((m) & GENMASK(4, 0)) + +#define IBI_MDB_GRP_PENDING_READ_NOTIF 0x5 +#define IS_MDB_PENDING_READ_NOTIFY(m) (IBI_MDB_GET_GRP(m) == IBI_MDB_GRP_PENDING_READ_NOTIF) +#define IBI_MDB_MIPI_DBGDATAREADY IBI_MDB_ID(IBI_MDB_GRP_PENDING_READ_NOTIF, 0xd) +#define IBI_MDB_MCTP IBI_MDB_ID(IBI_MDB_GRP_PENDING_READ_NOTIF, 0xe) +/* Interrupt ID 0x10 to 0x1F are for vendor specific */ +#define IBI_MDB_ASPEED IBI_MDB_ID(IBI_MDB_GRP_PENDING_READ_NOTIF, 0x1f) + +struct i3c_ibi_payload { + int max_payload_size; + int size; + uint8_t *buf; +}; + +/** + * @brief IBI callback function structure + * @param write_requested callback function to return a memory block for receiving IBI data + * @param write_done callback function to process the received IBI data + */ +struct i3c_ibi_callbacks { + struct i3c_ibi_payload* (*write_requested)(struct i3c_dev_desc *i3cdev); + void (*write_done)(struct i3c_dev_desc *i3cdev); +}; + +/* slave driver structure */ +struct i3c_slave_payload { + int size; + void *buf; +}; + +/* slave events */ +#define I3C_SLAVE_EVENT_SIR BIT(0) +#define I3C_SLAVE_EVENT_MR BIT(1) +#define I3C_SLAVE_EVENT_HJ BIT(2) + +/** + * @brief slave callback function structure + * @param write_requested callback function to return a memory block for receiving data sent from + * the master device + * @param write_done callback function to process the received IBI data + */ +struct i3c_slave_callbacks { + struct i3c_slave_payload* (*write_requested)(const struct device *dev); + void (*write_done)(const struct device *dev); +}; + +struct i3c_slave_setup { + int max_payload_len; + const struct device *dev; + const struct i3c_slave_callbacks *callbacks; +}; + +/* HAL API */ +int i3c_npcm4xx_master_attach_device(const struct device *dev, struct i3c_dev_desc *slave); +int i3c_npcm4xx_master_detach_device(const struct device *dev, struct i3c_dev_desc *slave); +int i3c_npcm4xx_master_send_ccc(const struct device *dev, struct i3c_ccc_cmd *ccc); +int i3c_npcm4xx_master_priv_xfer(struct i3c_dev_desc *i3cdev, struct i3c_priv_xfer *xfers, + int nxfers); +int i3c_npcm4xx_master_request_ibi(struct i3c_dev_desc *i3cdev, struct i3c_ibi_callbacks *cb); +int i3c_npcm4xx_master_enable_ibi(struct i3c_dev_desc *i3cdev); +int i3c_npcm4xx_master_send_entdaa(struct i3c_dev_desc *i3cdev); +int i3c_npcm4xx_slave_register(const struct device *dev, struct i3c_slave_setup *slave_data); + +/** + * @brief get the assigned dynamic address of the i3c controller + * @param dev the I3C controller in slave mode + * @param dynamic_addr pointer to the dynamic address variable + * @return -1 if dynamic address is not assigned + * @return 0 if dynamic address is assigned. The value is passed to `dynamic_addr` + */ +int i3c_npcm4xx_slave_get_dynamic_addr(const struct device *dev, uint8_t *dynamic_addr); + +/** + * @brief get the event enabling status + * @param dev the I3C controller in slave mode + * @param event_en pointer to the event enabling mask, see `I3C_SLAVE_EVENT_*`. + * @return 0 if success + * + * This function gets the status of the event enabling from the slave controller. + * The bits set in `event_en` means the corresponding slave events are enabled. + */ +int i3c_npcm4xx_slave_get_event_enabling(const struct device *dev, uint32_t *event_en); + +/** + * @brief slave device sends SIR (IBI) with data + * + * @param dev the I3C controller in slave mode + * @param payload pointer to IBI payload structure + * @return int 0 = success + */ +int i3c_npcm4xx_slave_send_sir(const struct device *dev, struct i3c_ibi_payload *payload); + +/** + * @brief slave device prepares the data for master private read transfer + * + * @param dev the I3C controller in slave mode + * @param data pointer to the data structure to be read + * @param ibi_notify pointer to the IBI notification structure (optional) + * @return int 0 = success + * + * This function puts the pending read data to the TX FIFO and waits until the + * pending read data is consumed. The API uses osEventFlagsWait and will make + * the caller thread sleep so do not call it in the ISR. + * If @ibi_notify is specified, a slave interrupt with the IBI payload will be + * issued to notify the master device that there is a pending read data. The + * master device shall issue a private read transfer to read the data back. + */ +int i3c_npcm4xx_slave_put_read_data(const struct device *dev, struct i3c_slave_payload *data, + struct i3c_ibi_payload *ibi_notify); + +/* common API */ +int i3c_master_send_enec(const struct device *master, uint8_t addr, uint8_t evt); +int i3c_master_send_disec(const struct device *master, uint8_t addr, uint8_t evt); +int i3c_master_send_rstdaa(const struct device *master); +int i3c_master_send_sethid(const struct device *master); +int i3c_master_send_aasa(const struct device *master); +int i3c_master_send_setmrl(const struct device *master, uint8_t addr, uint16_t mrl, + uint8_t ibi_payload_size); +int i3c_master_send_getpid(const struct device *master, uint8_t addr, uint64_t *pid); +int i3c_master_send_getbcr(const struct device *master, uint8_t addr, uint8_t *bcr); + +#define i3c_master_attach_device i3c_npcm4xx_master_attach_device +#define i3c_master_detach_device i3c_npcm4xx_master_detach_device +#define i3c_master_send_ccc i3c_npcm4xx_master_send_ccc +#define i3c_master_priv_xfer i3c_npcm4xx_master_priv_xfer +#define i3c_master_request_ibi i3c_npcm4xx_master_request_ibi +#define i3c_master_enable_ibi i3c_npcm4xx_master_enable_ibi +#define i3c_master_send_entdaa i3c_npcm4xx_master_send_entdaa +#define i3c_slave_register i3c_npcm4xx_slave_register +#define i3c_slave_send_sir i3c_npcm4xx_slave_send_sir +#define i3c_slave_put_read_data i3c_npcm4xx_slave_put_read_data +#define i3c_slave_get_dynamic_addr i3c_npcm4xx_slave_get_dynamic_addr +#define i3c_slave_get_event_enabling i3c_npcm4xx_slave_get_event_enabling + +int i3c_jesd403_read(struct i3c_dev_desc *slave, uint8_t *addr, int addr_size, uint8_t *data, + int data_size); +int i3c_jesd403_write(struct i3c_dev_desc *slave, uint8_t *addr, int addr_size, uint8_t *data, + int data_size); +int i3c_i2c_read(struct i3c_dev_desc *slave, uint8_t addr, uint8_t *buf, int length); +int i3c_i2c_write(struct i3c_dev_desc *slave, uint8_t addr, uint8_t *buf, int length); diff --git a/soc/arm/npcm4xx/common/reg/reg_def.h b/soc/arm/npcm4xx/common/reg/reg_def.h index 5dc9a40e8ab1f1..cbee899a704747 100644 --- a/soc/arm/npcm4xx/common/reg/reg_def.h +++ b/soc/arm/npcm4xx/common/reg/reg_def.h @@ -7,6 +7,12 @@ #ifndef _NUVOTON_NPCM4XX_REG_DEF_H #define _NUVOTON_NPCM4XX_REG_DEF_H +#define __I volatile const /*!< Defines 'read only' permissions */ +#define __O volatile /*!< Defines 'write only' permissions */ +#define __IO volatile /*!< Defines 'read / write' permissions */ + +#define CHIP_ID_NPCM4XX 5832 + /* * NPCM4XX register structure size/offset checking macro function to mitigate * the risk of unexpected compiling results. All addresses of NPCM4XX registers @@ -200,6 +206,8 @@ struct scfg_reg { #define NPCM4XX_DEVPU1_F_SPI_PUD_EN 7 #define NPCM4XX_DEVALTCX_GPIO_PULL_EN 7 +#define SCFG_BASE_ADDR (0x400C3000) + /* * System Glue (GLUE) device registers */ @@ -1706,4 +1714,451 @@ struct peci_reg { #define NPCM4XX_PECI_RATE_EHSP 6 #define NPCM4XX_PECI_RATE_HLOAD 7 +struct i3c_reg { + /* 0x000: Master Configuration */ + volatile uint32_t MCONFIG; + /* 0x004: Configuration */ + volatile uint32_t CONFIG; + /* 0x008: Status */ + volatile uint32_t STATUS; + /* 0x00C: I3C Control */ + volatile uint32_t CTRL; + /* 0x010: Interrupt Enable Set */ + volatile uint32_t INTSET; + /* 0x014: Interrupt Enable Clear */ + volatile uint32_t INTCLR; + /* 0x018: Interrupt Masked */ + volatile uint32_t INTMASKED; + /* 0x01C: Error and Warning */ + volatile uint32_t ERRWARN; + /* 0x020: DMA Control */ + volatile uint32_t DMACTRL; + volatile uint8_t RESERVE0[8]; + /* 0x02C: Data Control */ + volatile uint32_t DATACTRL; + /* 0x030: Write Byte Data */ + volatile uint32_t WDATAB; + /* 0x034: Write Byte Data as End */ + volatile uint32_t WDATABE; + /* 0x038: Write Half-Word Data */ + volatile uint32_t WDATAH; + /* 0x03C: Write Half-Word Data as End */ + volatile uint32_t WDATAHE; + /* 0x040: Read Byte Data */ + volatile uint32_t RDATAB; + volatile uint8_t RESERVE1[4]; + /* 0x048: Read Half-Word Data */ + volatile uint32_t RDATAH; + volatile uint8_t RESERVE2[8]; + /* 0x054: Byte-Only Write Byte Data */ + volatile uint8_t WDATAB1; + volatile uint8_t RESERVE3[11]; + /* 0x060: Capabilities */ + volatile uint32_t CAPABILITIES; + /* 0x064: Dynamic Address */ + volatile uint32_t DYNADDR; + /* 0x068: Maximum Limits */ + volatile uint32_t MAXLIMITS; + /* 0x06C: Part Number */ + volatile uint32_t PARTNO; + /* 0x070: ID Extension */ + volatile uint32_t IDEXT; + /* 0x074: Vendor ID */ + volatile uint32_t VENDORID; + /* 0x078: Timing Control Clock */ + volatile uint32_t TCCLOCK; + volatile uint8_t RESERVE4[8]; + /* 0x084: Master Control */ + volatile uint32_t MCTRL; + /* 0x088: Master Status */ + volatile uint32_t MSTATUS; + /* 0x08C: IBI Registry and Rules */ + volatile uint32_t IBIRULES; + /* 0x090: Master Interrupt Enable Set */ + volatile uint32_t MINTSET; + /* 0x094: Master Interrupt Enable Clear */ + volatile uint32_t MINTCLR; + /* 0x098: Master Interrupt Masked */ + volatile uint32_t MINTMASKED; + /* 0x09C: Master Error and Warning */ + volatile uint32_t MERRWARN; + /* 0x0A0: Master DMA Control */ + volatile uint32_t MDMACTRL; + volatile uint8_t RESERVE5[8]; + /* 0x0AC: Master Data Control */ + volatile uint32_t MDATACTRL; + /* 0x0B0: Master Write Byte Data */ + volatile uint32_t MWDATAB; + /* 0x0B4: Master Write Byte Data as End */ + volatile uint32_t MWDATABE; + /* 0x0B8: Master Write Half-Word Data */ + volatile uint32_t MWDATAH; + /* 0x0BC: Master Write Half-Word Data as End */ + volatile uint32_t MWDATAHE; + /* 0x0C0: Master Read Byte Data */ + volatile uint32_t MRDATAB; + volatile uint8_t RESERVE6[4]; + /* 0x0C8: Master Read Half-Word Data */ + volatile uint32_t MRDATAH; + /* 0x0CC: Master Byte-Only Write Byte Data */ + volatile uint8_t MWDATAB1; + volatile uint8_t RESERVE7[3]; + /* 0x0D0: Start or Continue SDR Message */ + union { + volatile uint32_t MWMSG_SDR; + volatile uint32_t MWMSG_SDR_CONTROL; + volatile uint32_t MWMSG_SDR_DATA; + }; + /* 0x0D4: Read SDR Message Data */ + volatile uint32_t MRMSG_SDR; + /* 0x0D8: Start or Continue DDR Message */ + union { + volatile uint32_t MWMSG_DDR; + volatile uint32_t MWMSG_DDR_CONTROL; + volatile uint32_t MWMSG_DDR_ADDRCMD; + volatile uint32_t MWMSG_DDR_DATA; + }; + /* 0x0DC: Read DDR Message Data */ + volatile uint32_t MRMSG_DDR; + volatile uint8_t RESERVE8[4]; + /* 00xE4: Master Dynamic Address */ + volatile uint32_t MDYNADDR; + volatile uint8_t RESERVE9[32]; + /* 0x108: HDR Command Register */ + volatile uint32_t HDRCMD; + volatile uint8_t RESERVE10[52]; + /* 0x140: Extended IBI Data Register 1 */ + volatile uint32_t IBIEXT1; + /* 0x144: Extended IBI Data Register 2 */ + volatile uint32_t IBIEXT2; + volatile uint8_t RESERVE11[180]; + /* 0x1FC: Block ID */ + volatile uint32_t ID; +}; + +#define I3C_BASE_ADDR(mdl) (0x40004000 + ((mdl) * 0x0400L)) + +/* I3C register fields */ +#define NPCM4XX_I3C_MCONFIG_I2CBAUD FIELD(28, 31) +#define NPCM4XX_I3C_MCONFIG_ODHPP 24 +#define NPCM4XX_I3C_MCONFIG_ODBAUD FIELD(16, 23) +#define NPCM4XX_I3C_MCONFIG_PPLOW FIELD(12, 15) +#define NPCM4XX_I3C_MCONFIG_PPBAUD FIELD(8, 11) +#define NPCM4XX_I3C_MCONFIG_ODSTOP 6 +#define NPCM4XX_I3C_MCONFIG_DISTO 3 +#define NPCM4XX_I3C_MCONFIG_MSTENA FIELD(0, 1) +#define NPCM4XX_I3C_CONFIG_SADDR FIELD(25, 31) +#define NPCM4XX_I3C_CONFIG_BAMATCH FIELD(16, 22) +#define NPCM4XX_I3C_CONFIG_HDRCMD 10 +#define NPCM4XX_I3C_CONFIG_OFFLINE 9 +#define NPCM4XX_I3C_CONFIG_IDRAND 8 +#define NPCM4XX_I3C_CONFIG_DDROK 4 +#define NPCM4XX_I3C_CONFIG_S0IGNORE 3 +#define NPCM4XX_I3C_CONFIG_MATCHSS 2 +#define NPCM4XX_I3C_CONFIG_NACK 1 +#define NPCM4XX_I3C_CONFIG_SLVENA 0 +#define NPCM4XX_I3C_STATUS_TIMECTRL FIELD(30, 31) +#define NPCM4XX_I3C_STATUS_ACTSTATE FIELD(28, 29) +#define NPCM4XX_I3C_STATUS_HJDIS 27 +#define NPCM4XX_I3C_STATUS_MRDIS 25 +#define NPCM4XX_I3C_STATUS_IBIDIS 24 +#define NPCM4XX_I3C_STATUS_EVDET FIELD(20, 21) +#define NPCM4XX_I3C_STATUS_EVENT 18 +#define NPCM4XX_I3C_STATUS_CHANDLED 17 +#define NPCM4XX_I3C_STATUS_DDRMATCH 16 +#define NPCM4XX_I3C_STATUS_ERRWARN 15 +#define NPCM4XX_I3C_STATUS_CCC 14 +#define NPCM4XX_I3C_STATUS_DACHG 13 +#define NPCM4XX_I3C_STATUS_TXNOTFULL 12 +#define NPCM4XX_I3C_STATUS_RXPEND 11 +#define NPCM4XX_I3C_STATUS_STOP 10 +#define NPCM4XX_I3C_STATUS_MATCHED 9 +#define NPCM4XX_I3C_STATUS_START 8 +#define NPCM4XX_I3C_STATUS_STHDR 6 +#define NPCM4XX_I3C_STATUS_STDAA 5 +#define NPCM4XX_I3C_STATUS_STREQWR 4 +#define NPCM4XX_I3C_STATUS_STREQRD 3 +#define NPCM4XX_I3C_STATUS_STCCCH 2 +#define NPCM4XX_I3C_STATUS_STMSG 1 +#define NPCM4XX_I3C_STATUS_STNOTSTOP 0 +#define NPCM4XX_I3C_CTRL_VENDINFO FIELD(24, 31) +#define NPCM4XX_I3C_CTRL_ACTSTATE FIELD(20, 21) +#define NPCM4XX_I3C_CTRL_PENDINT FIELD(16, 19) +#define NPCM4XX_I3C_CTRL_IBIDATA FIELD(8, 15) +#define NPCM4XX_I3C_CTRL_EXTDATA 3 +#define NPCM4XX_I3C_CTRL_EVENT FIELD(0, 1) +#define NPCM4XX_I3C_INTSET_EVENT 18 +#define NPCM4XX_I3C_INTSET_CHANDLED 17 +#define NPCM4XX_I3C_INTSET_DDRMATCHED 16 +#define NPCM4XX_I3C_INTSET_ERRWARN 15 +#define NPCM4XX_I3C_INTSET_CCC 14 +#define NPCM4XX_I3C_INTSET_DACHG 13 +#define NPCM4XX_I3C_INTSET_TXNOTFULL 12 +#define NPCM4XX_I3C_INTSET_RXPEND 11 +#define NPCM4XX_I3C_INTSET_STOP 10 +#define NPCM4XX_I3C_INTSET_MATCHED 9 +#define NPCM4XX_I3C_INTSET_START 8 +#define NPCM4XX_I3C_INTCLR_EVENT 18 +#define NPCM4XX_I3C_INTCLR_CHANDLED 17 +#define NPCM4XX_I3C_INTCLR_DDRMATCHED 16 +#define NPCM4XX_I3C_INTCLR_ERRWARN 15 +#define NPCM4XX_I3C_INTCLR_CCC 14 +#define NPCM4XX_I3C_INTCLR_DACHG 13 +#define NPCM4XX_I3C_INTCLR_TXNOTFULL 12 +#define NPCM4XX_I3C_INTCLR_RXPEND 11 +#define NPCM4XX_I3C_INTCLR_STOP 10 +#define NPCM4XX_I3C_INTCLR_MATCHED 9 +#define NPCM4XX_I3C_INTCLR_START 8 +#define NPCM4XX_I3C_INTMASKED_EVENT 18 +#define NPCM4XX_I3C_INTMASKED_CHANDLED 17 +#define NPCM4XX_I3C_INTMASKED_DDRMATCHED 16 +#define NPCM4XX_I3C_INTMASKED_ERRWARN 15 +#define NPCM4XX_I3C_INTMASKED_CCC 14 +#define NPCM4XX_I3C_INTMASKED_DACHG 13 +#define NPCM4XX_I3C_INTMASKED_TXNOTFULL 12 +#define NPCM4XX_I3C_INTMASKED_RXPEND 11 +#define NPCM4XX_I3C_INTMASKED_STOP 10 +#define NPCM4XX_I3C_INTMASKED_MATCHED 9 +#define NPCM4XX_I3C_INTMASKED_START 8 +#define NPCM4XX_I3C_ERRWARN_OWRITE 17 +#define NPCM4XX_I3C_ERRWARN_OREAD 16 +#define NPCM4XX_I3C_ERRWARN_S0S1 11 +#define NPCM4XX_I3C_ERRWARN_HCRC 10 +#define NPCM4XX_I3C_ERRWARN_HPAR 9 +#define NPCM4XX_I3C_ERRWARN_SPAR 8 +#define NPCM4XX_I3C_ERRWARN_INVSTART 4 +#define NPCM4XX_I3C_ERRWARN_TERM 3 +#define NPCM4XX_I3C_ERRWARN_URUNNACK 2 +#define NPCM4XX_I3C_ERRWARN_URUN 1 +#define NPCM4XX_I3C_ERRWARN_ORUN 0 +#define NPCM4XX_I3C_DMACTRL_DMAWIDTH FIELD(4, 5) +#define NPCM4XX_I3C_DMACTRL_DMATB FIELD(2, 3) +#define NPCM4XX_I3C_DMACTRL_DMAFB FIELD(0, 1) +#define NPCM4XX_I3C_DATACTRL_RXEMPTY 31 +#define NPCM4XX_I3C_DATACTRL_TXFULL 30 +#define NPCM4XX_I3C_DATACTRL_RXCOUNT FIELD(24, 28) +#define NPCM4XX_I3C_DATACTRL_TXCOUNT FIELD(16, 20) +#define NPCM4XX_I3C_DATACTRL_RXTRIG FIELD(6, 7) +#define NPCM4XX_I3C_DATACTRL_TXTRIG FIELD(4, 5) +#define NPCM4XX_I3C_DATACTRL_UNLOCK 3 +#define NPCM4XX_I3C_DATACTRL_FLUSHFB 1 +#define NPCM4XX_I3C_DATACTRL_FLUSHTB 0 +#define NPCM4XX_I3C_WDATAB_END_A 16 +#define NPCM4XX_I3C_WDATAB_END_B 8 +#define NPCM4XX_I3C_WDATAB_DATA FIELD(0, 7) +#define NPCM4XX_I3C_WDATABE_DATA FIELD(0, 7) +#define NPCM4XX_I3C_WDATAH_END 16 +#define NPCM4XX_I3C_WDATAH_DATA1 FIELD(8, 15) +#define NPCM4XX_I3C_WDATAH_DATA0 FIELD(0, 7) +#define NPCM4XX_I3C_WDATAHE_DATA1 FIELD(8, 15) +#define NPCM4XX_I3C_WDATAHE_DATA0 FIELD(0, 7) +#define NPCM4XX_I3C_RDATAB_DATA0 FIELD(0, 7) +#define NPCM4XX_I3C_RDATAH_DATA1 FIELD(8, 15) +#define NPCM4XX_I3C_RDATAH_DATA0 FIELD(0, 7) +#define NPCM4XX_I3C_WDATAB1_DATA FIELD(0, 7) +#define NPCM4XX_I3C_CAPABILITIES_DMA 31 +#define NPCM4XX_I3C_CAPABILITIES_INT 30 +#define NPCM4XX_I3C_CAPABILITIES_FIFORX FIELD(28, 29) +#define NPCM4XX_I3C_CAPABILITIES_FIFOTX FIELD(26, 27) +#define NPCM4XX_I3C_CAPABILITIES_TIMECTRL 21 +#define NPCM4XX_I3C_CAPABILITIES_IBI_MR_HJ FIELD(16, 20) +#define NPCM4XX_I3C_CAPABILITIES_CCCHANDLE FIELD(12, 15) +#define NPCM4XX_I3C_CAPABILITIES_SADDR FIELD(10, 11) +#define NPCM4XX_I3C_CAPABILITIES_HDRSUPP 6 +#define NPCM4XX_I3C_CAPABILITIES_IDREG FIELD(2, 5) +#define NPCM4XX_I3C_CAPABILITIES_IDENA FIELD(0, 1) +#define NPCM4XX_I3C_DYNADDR_DADDR FIELD(1, 7) +#define NPCM4XX_I3C_DYNADDR_DAVALID 0 +#define NPCM4XX_I3C_MAXLIMITS_MAXWR FIELD(16, 27) +#define NPCM4XX_I3C_MAXLIMITS_MAXRD FIELD(0, 11) +#define NPCM4XX_I3C_PARTNO_PARTNO FIELD(0, 31) +#define NPCM4XX_I3C_IDEXT_BCR FIELD(16, 23) +#define NPCM4XX_I3C_IDEXT_DCR FIELD(8, 15) +#define NPCM4XX_I3C_VENDORID_VID FIELD(0, 14) +#define NPCM4XX_I3C_TCCLOCK_FREQ FIELD(8, 15) +#define NPCM4XX_I3C_TCCLOCK_ACCURACY FIELD(0, 7) +#define NPCM4XX_I3C_MCTRL_RDTERM FIELD(16, 23) +#define NPCM4XX_I3C_MCTRL_ADDR FIELD(9, 15) +#define NPCM4XX_I3C_MCTRL_DIR 8 +#define NPCM4XX_I3C_MCTRL_IBIRESP FIELD(6, 7) +#define NPCM4XX_I3C_MCTRL_TYPE FIELD(4, 5) +#define NPCM4XX_I3C_MCTRL_REQUEST FIELD(0, 2) +#define NPCM4XX_I3C_MSTATUS_IBIADDR FIELD(24, 30) +#define NPCM4XX_I3C_MSTATUS_NOWMASTER 19 +#define NPCM4XX_I3C_MSTATUS_ERRWARN 15 +#define NPCM4XX_I3C_MSTATUS_IBIWON 13 +#define NPCM4XX_I3C_MSTATUS_TXNOTFULL 12 +#define NPCM4XX_I3C_MSTATUS_RXPEND 11 +#define NPCM4XX_I3C_MSTATUS_COMPLETE 10 +#define NPCM4XX_I3C_MSTATUS_MCTRLDONE 9 +#define NPCM4XX_I3C_MSTATUS_SLVSTART 8 +#define NPCM4XX_I3C_MSTATUS_IBITYPE FIELD(6, 7) +#define NPCM4XX_I3C_MSTATUS_NACKED 5 +#define NPCM4XX_I3C_MSTATUS_BETWEEN 4 +#define NPCM4XX_I3C_MSTATUS_STATE FIELD(0, 2) +#define NPCM4XX_I3C_IBIRULES_NOBYTE 31 +#define NPCM4XX_I3C_IBIRULES_MSB0 30 +#define NPCM4XX_I3C_IBIRULES_ADDR4 FIELD(24, 29) +#define NPCM4XX_I3C_IBIRULES_ADDR3 FIELD(18, 23) +#define NPCM4XX_I3C_IBIRULES_ADDR2 FIELD(12, 17) +#define NPCM4XX_I3C_IBIRULES_ADDR1 FIELD(6, 11) +#define NPCM4XX_I3C_IBIRULES_ADDR0 FIELD(0, 5) +#define NPCM4XX_I3C_MINTSET_NOWMASTER 19 +#define NPCM4XX_I3C_MINTSET_ERRWARN 15 +#define NPCM4XX_I3C_MINTSET_IBIWON 13 +#define NPCM4XX_I3C_MINTSET_TXNOTFULL 12 +#define NPCM4XX_I3C_MINTSET_RXPEND 11 +#define NPCM4XX_I3C_MINTSET_COMPLETE 10 +#define NPCM4XX_I3C_MINTSET_MCTRLDONE 9 +#define NPCM4XX_I3C_MINTSET_SLVSTART 8 +#define NPCM4XX_I3C_MINTCLR_NOWMASTER 19 +#define NPCM4XX_I3C_MINTCLR_ERRWARN 15 +#define NPCM4XX_I3C_MINTCLR_IBIWON 13 +#define NPCM4XX_I3C_MINTCLR_TXNOTFULL 12 +#define NPCM4XX_I3C_MINTCLR_RXPEND 11 +#define NPCM4XX_I3C_MINTCLR_COMPLETE 10 +#define NPCM4XX_I3C_MINTCLR_MCTRLDONE 9 +#define NPCM4XX_I3C_MINTCLR_SLVSTART 8 +#define NPCM4XX_I3C_MINTMASKED_NOWMASTER 19 +#define NPCM4XX_I3C_MINTMASKED_ERRWARN 15 +#define NPCM4XX_I3C_MINTMASKED_IBIWON 13 +#define NPCM4XX_I3C_MINTMASKED_TXNOTFULL 12 +#define NPCM4XX_I3C_MINTMASKED_RXPEND 11 +#define NPCM4XX_I3C_MINTMASKED_COMPLETE 10 +#define NPCM4XX_I3C_MINTMASKED_MCTRLDONE 9 +#define NPCM4XX_I3C_MINTMASKED_SLVSTART 8 +#define NPCM4XX_I3C_MERRWARN_TIMEOUT 20 +#define NPCM4XX_I3C_MERRWARN_INVREQ 19 +#define NPCM4XX_I3C_MERRWARN_MSGERR 18 +#define NPCM4XX_I3C_MERRWARN_OWRITE 17 +#define NPCM4XX_I3C_MERRWARN_OREAD 16 +#define NPCM4XX_I3C_MERRWARN_HCRC 10 +#define NPCM4XX_I3C_MERRWARN_HPAR 9 +#define NPCM4XX_I3C_MERRWARN_TERM 4 +#define NPCM4XX_I3C_MERRWARN_WRABT 3 +#define NPCM4XX_I3C_MERRWARN_NACK 2 +#define NPCM4XX_I3C_MDMACTRL_DMAWIDTH FIELD(4, 5) +#define NPCM4XX_I3C_MDMACTRL_DMATB FIELD(2, 3) +#define NPCM4XX_I3C_MDMACTRL_DMAFB FIELD(0, 1) +#define NPCM4XX_I3C_MDATACTRL_RXEMPTY 31 +#define NPCM4XX_I3C_MDATACTRL_TXFULL 30 +#define NPCM4XX_I3C_MDATACTRL_RXCOUNT FIELD(24, 28) +#define NPCM4XX_I3C_MDATACTRL_TXCOUNT FIELD(16, 20) +#define NPCM4XX_I3C_MDATACTRL_RXTRIG FIELD(6, 7) +#define NPCM4XX_I3C_MDATACTRL_TXTRIG FIELD(4, 5) +#define NPCM4XX_I3C_MDATACTRL_UNLOCK 3 +#define NPCM4XX_I3C_MDATACTRL_FLUSHFB 1 +#define NPCM4XX_I3C_MDATACTRL_FLUSHTB 0 +#define NPCM4XX_I3C_MWDATAB_END_A 16 +#define NPCM4XX_I3C_MWDATAB_END_B 8 +#define NPCM4XX_I3C_MWDATAB_DATA FIELD(0, 7) +#define NPCM4XX_I3C_MWDATABE_DATA FIELD(0, 7) +#define NPCM4XX_I3C_MWDATAH_END 16 +#define NPCM4XX_I3C_MWDATAH_DATA1 FIELD(8, 15) +#define NPCM4XX_I3C_MWDATAH_DATA0 FIELD(0, 7) +#define NPCM4XX_I3C_MWDATAHE_DATA1 FIELD(8, 15) +#define NPCM4XX_I3C_MWDATAHE_DATA0 FIELD(0, 7) +#define NPCM4XX_I3C_MRDATAB_DATA FIELD(0, 7) +#define NPCM4XX_I3C_MRDATAH_DATA1 FIELD(8, 15) +#define NPCM4XX_I3C_MRDATAH_DATA0 FIELD(0, 7) +#define NPCM4XX_I3C_MWDATAB1_DATA FIELD(0, 7) +#define NPCM4XX_I3C_MWMSG_SDR_CONTROL_LEN FIELD(11, 15) +#define NPCM4XX_I3C_MWMSG_SDR_CONTROL_I2C 10 +#define NPCM4XX_I3C_MWMSG_SDR_CONTROL_END 8 +#define NPCM4XX_I3C_MWMSG_SDR_CONTROL_ADDR FIELD(1, 7) +#define NPCM4XX_I3C_MWMSG_SDR_CONTROL_DIR 0 +#define NPCM4XX_I3C_MWMSG_SDR_DATA_DATA16B FIELD(0, 15) +#define NPCM4XX_I3C_MRMSG_SDR_DATA FIELD(0, 15) +#define NPCM4XX_I3C_MWMSG_DDR_CONTROL_END 14 +#define NPCM4XX_I3C_MWMSG_DDR_CONTROL_LEN FIELD(0, 9) +#define NPCM4XX_I3C_MWMSG_DDR_CONTROL_ADDR FIELD(9, 15) +#define NPCM4XX_I3C_MWMSG_DDR_CONTROL_DIR 7 +#define NPCM4XX_I3C_MWMSG_DDR_CONTROL_CMD FIELD(0, 6) +#define NPCM4XX_I3C_MWMSG_DDR_DATA_DATA16B FIELD(0, 15) +#define NPCM4XX_I3C_MRMSG_DDR_DATA FIELD(0, 15) +#define NPCM4XX_I3C_MDYNADDR_DADDR FIELD(1, 7) +#define NPCM4XX_I3C_MDYNADDR_DAVALID 0 +#define NPCM4XX_I3C_HDRCMD_NEWCMD 31 +#define NPCM4XX_I3C_HDRCMD_OVFLW 30 +#define NPCM4XX_I3C_HDRCMD_CMD0 FIELD(0, 7) +#define NPCM4XX_I3C_IBIEXT1_EXT3 FIELD(24, 31) +#define NPCM4XX_I3C_IBIEXT1_EXT2 FIELD(16, 23) +#define NPCM4XX_I3C_IBIEXT1_EXT1 FIELD(8, 15) +#define NPCM4XX_I3C_IBIEXT1_MAX FIELD(4, 6) +#define NPCM4XX_I3C_IBIEXT1_CNT FIELD(0, 2) +#define NPCM4XX_I3C_IBIEXT2_EXT7 FIELD(24, 31) +#define NPCM4XX_I3C_IBIEXT2_EXT6 FIELD(16, 23) +#define NPCM4XX_I3C_IBIEXT2_EXT5 FIELD(8, 15) +#define NPCM4XX_I3C_IBIEXT2_EXT4 FIELD(0, 7) +#define NPCM4XX_I3C_SID_ID FIELD(0, 31) + +struct dsct_reg { + __IO uint32_t CTL; + __IO uint32_t ENDSA; + __IO uint32_t ENDDA; + __IO uint32_t NEXT; +}; + +struct pdma_reg { + __IO struct dsct_reg DSCT[16]; + + __I uint32_t RESERVE0[192]; + + __IO uint32_t CHCTL; + + __O uint32_t STOP; + + __O uint32_t SWREQ; + + __I uint32_t TRGSTS; + + __IO uint32_t PRISET; + + __O uint32_t PRICLR; + + __IO uint32_t INTEN; + + __IO uint32_t INTSTS; + + __IO uint32_t ABTSTS; + + __IO uint32_t TDSTS; + + __IO uint32_t SCATSTS; + + __I uint32_t TACTSTS; + + __I uint32_t RESERVE1[3]; + + __IO uint32_t SCATBA; + + __IO uint32_t TOC0_1; + + __IO uint32_t TOC2_3; + + __IO uint32_t TOC4_5; + + __IO uint32_t TOC6_7; + + __IO uint32_t TOC8_9; + + __IO uint32_t TOC10_11; + + __IO uint32_t TOC12_13; + + __IO uint32_t TOC14_15; + + __I uint32_t RESERVE2[8]; + + __IO uint32_t REQSEL0_3; + + __IO uint32_t REQSEL4_7; + + __IO uint32_t REQSEL8_11; + + __IO uint32_t REQSEL12_15; +}; + +#define PDMA_BASE_ADDR (0x40015000) + #endif /* _NUVOTON_NPCM4XX_REG_DEF_H */ diff --git a/soc/arm/npcm4xx/npcm400f/sig_def_list.h b/soc/arm/npcm4xx/npcm400f/sig_def_list.h index c2694482ec6fac..93dcfbeb92b705 100644 --- a/soc/arm/npcm4xx/npcm400f/sig_def_list.h +++ b/soc/arm/npcm4xx/npcm400f/sig_def_list.h @@ -150,3 +150,17 @@ SIG_DEFINE(SPIP_DIO1, B12, SIG_DESC_SET(0x1c, 1)) SIG_DEFINE(SPIP_DIO2, A11, SIG_DESC_SET(0x1c, 1), SIG_DESC_CLEAR(0x04, 2)) SIG_DEFINE(SPIP_DIO3, A10, SIG_DESC_SET(0x1c, 1)) #endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(i3c0), okay) && CONFIG_I3C_NPCM4XX +/* DEVALT7.3=0, DEVALT7.2=1 */ +SIG_DEFINE(I3C1_SCL, A5, SIG_DESC_CLEAR(0x17, 3), SIG_DESC_SET(0x17, 2)) +/* DEVALT7.4=0, DEVALT5.4=0, DEVALT7.2=1 */ +SIG_DEFINE(I3C1_SDA, B5, SIG_DESC_CLEAR(0x17, 4), SIG_DESC_CLEAR(0x15, 4), SIG_DESC_SET(0x29, 2)) +#endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(i3c1), okay) && CONFIG_I3C_NPCM4XX +/* DEVALTA.4=1 */ +SIG_DEFINE(I3C2_SCL, B9, SIG_DESC_SET(0x1A, 4)) +/* DEVALTA.4=1 */ +SIG_DEFINE(I3C2_SDA, A9, SIG_DESC_SET(0x1A, 4)) +#endif diff --git a/tests/boards/npcm400f_evb/CMakeLists.txt b/tests/boards/npcm400f_evb/CMakeLists.txt new file mode 100644 index 00000000000000..683ed7babb01ae --- /dev/null +++ b/tests/boards/npcm400f_evb/CMakeLists.txt @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.13.1) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(npcm400f_evb_test) + +#FILE(GLOB app_sources src/*.c src/test_gpio/test*.c) +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/boards/npcm400f_evb/dts/bindings/test,gpio_basic_api.yaml b/tests/boards/npcm400f_evb/dts/bindings/test,gpio_basic_api.yaml new file mode 100644 index 00000000000000..ee31c12a07d8c9 --- /dev/null +++ b/tests/boards/npcm400f_evb/dts/bindings/test,gpio_basic_api.yaml @@ -0,0 +1,28 @@ +# +# Copyright (c) 2019 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +description: | + This binding provides resources required to build and run the + tests/drivers/gpio/gpio_basic_api test in Zephyr. + +compatible: "test,gpio_basic_api" + +properties: + out-gpios: + type: phandle-array + required: true + description: | + Identity of a GPIO that will be configured as an output. This + must be on the same device as in-gpios, and physically + connected to in-gpios. + + in-gpios: + type: phandle-array + required: true + description: | + Identity of a GPIO that will be configured as an input. This + must be on the same device as out-gpios,and physically + connected to out-gpios. diff --git a/tests/boards/npcm400f_evb/prj.conf b/tests/boards/npcm400f_evb/prj.conf new file mode 100644 index 00000000000000..4a276847072a3e --- /dev/null +++ b/tests/boards/npcm400f_evb/prj.conf @@ -0,0 +1,31 @@ +CONFIG_THREAD_RUNTIME_STATS=y + +CONFIG_ZTEST=y + +CONFIG_I3C=y +#CONFIG_I3C_SLAVE=y +#CONFIG_I3C_SLAVE_MQUEUE=y + +#CONFIG_SHELL=y +#CONFIG_SHELL_BACKEND_SERIAL_INIT_PRIORITY=99 + +CONFIG_MAIN_STACK_SIZE=16384 +CONFIG_ISR_STACK_SIZE=8192 +CONFIG_ZTEST_STACKSIZE=16384 +CONFIG_IDLE_STACK_SIZE=4096 +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=8192 +CONFIG_TEST_EXTRA_STACKSIZE=8192 +CONFIG_PRIVILEGED_STACK_SIZE=4096 +#CONFIG_SHELL_STACK_SIZE=8192 + +CONFIG_NO_OPTIMIZATIONS=y + +CONFIG_HEAP_MEM_POOL_SIZE=16384 +CONFIG_STACK_SENTINEL=y +CONFIG_LOG=y + +CONFIG_THREAD_ANALYZER=y + +# Following configuration declare for rand32 +CONFIG_ENTROPY_GENERATOR=y +CONFIG_TEST_RANDOM_GENERATOR=y diff --git a/tests/boards/npcm400f_evb/src/ast_test.h b/tests/boards/npcm400f_evb/src/ast_test.h new file mode 100644 index 00000000000000..7749fa33ea8b70 --- /dev/null +++ b/tests/boards/npcm400f_evb/src/ast_test.h @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2021 Aspeedtech Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ASPEED_TESTSUITE_ZTEST_H_ +#define ASPEED_TESTSUITE_ZTEST_H_ + +#include +#include +#include +#include +#include + +#define AST_TEST_PASS 0 +#define AST_TEST_FAIL -1 + +enum aspeed_test_type { + AST_TEST_CI = 0, + AST_TEST_SLT, + AST_TEST_FT, +}; + +struct aspeed_test_param { + enum aspeed_test_type type; + const char *name; + int test_count; + int timeout; +}; + +struct aspeed_tests { + const char *name; + int (*test)(int count, enum aspeed_test_type); + int results; +}; + +static bool ast_test_fail; + +const char *ztest_relative_filename(const char *file); + +static inline bool aspeed_zassert(bool cond, + const char *default_msg, + const char *file, + int line, const char *func, + const char *msg, ...) +{ + if (cond == false) { + va_list vargs; + + va_start(vargs, msg); + PRINT("\n Assertion failed at %s:%d: %s: %s\n", + ztest_relative_filename(file), line, func, default_msg); + vprintk(msg, vargs); + printk("\n"); + va_end(vargs); + ast_test_fail = true; + return false; + } + + return true; +} + +static inline int ast_test_result(void) +{ + return ast_test_fail ? AST_TEST_FAIL : AST_TEST_PASS; +} + +#define ast_ztest_result() ast_test_result() + +/** + * @defgroup ztest_assert Ztest assertion macros + * @ingroup ztest + * + * This module provides assertions when using Ztest. + * + * @{ + */ + +/** + * @brief Fail the test, if @a cond is false + * + * You probably don't need to call this macro directly. You should + * instead use zassert_{condition} macros below. + * + * Note that when CONFIG_MULTITHREADING=n macro returns from the function. It is + * then expected that in that case ztest asserts will be used only in the + * context of the test function. + * + * @param cond Condition to check + * @param msg Optional, can be NULL. Message to print if @a cond is false. + * @param default_msg Message to print if @a cond is false + */ +#define ast_zassert(cond, default_msg, msg, ...) \ + aspeed_zassert(cond, msg ? ("(" default_msg ")") : (default_msg), \ + __FILE__, __LINE__, __func__, \ + msg ? msg : "", ##__VA_ARGS__); + +/** + * @brief Assert that this function call won't be reached + * @param msg Optional message to print if the assertion fails + */ +#define ast_zassert_unreachable(msg, ...) ast_zassert(0, "Reached unreachable code", \ + msg, ##__VA_ARGS__) + +/** + * @brief Assert that @a cond is true + * @param cond Condition to check + * @param msg Optional message to print if the assertion fails + */ +#define ast_zassert_true(cond, msg, ...) ast_zassert(cond, #cond " is false", \ + msg, ##__VA_ARGS__) + +/** + * @brief Assert that @a cond is false + * @param cond Condition to check + * @param msg Optional message to print if the assertion fails + */ +#define ast_zassert_false(cond, msg, ...) ast_zassert(!(cond), #cond " is true", \ + msg, ##__VA_ARGS__) + +/** + * @brief Assert that @a cond is 0 (success) + * @param cond Condition to check + * @param msg Optional message to print if the assertion fails + */ +#define ast_zassert_ok(cond, msg, ...) ast_zassert(!(cond), #cond " is non-zero", \ + msg, ##__VA_ARGS__) + +/** + * @brief Assert that @a ptr is NULL + * @param ptr Pointer to compare + * @param msg Optional message to print if the assertion fails + */ +#define ast_zassert_is_null(ptr, msg, ...) ast_zassert((ptr) == NULL, \ + #ptr " is not NULL", \ + msg, ##__VA_ARGS__) + +/** + * @brief Assert that @a ptr is not NULL + * @param ptr Pointer to compare + * @param msg Optional message to print if the assertion fails + */ +#define ast_zassert_not_null(ptr, msg, ...) ast_zassert((ptr) != NULL, \ + #ptr " is NULL", msg, \ + ##__VA_ARGS__) + +/** + * @brief Assert that @a a equals @a b + * + * @a a and @a b won't be converted and will be compared directly. + * + * @param a Value to compare + * @param b Value to compare + * @param msg Optional message to print if the assertion fails + */ +#define ast_zassert_equal(a, b, msg, ...) ast_zassert((a) == (b), \ + #a " not equal to " #b, \ + msg, ##__VA_ARGS__) + +/** + * @brief Assert that @a a does not equal @a b + * + * @a a and @a b won't be converted and will be compared directly. + * + * @param a Value to compare + * @param b Value to compare + * @param msg Optional message to print if the assertion fails + */ +#define ast_zassert_not_equal(a, b, msg, ...) ast_zassert((a) != (b), \ + #a " equal to " #b, \ + msg, ##__VA_ARGS__) + +/** + * @brief Assert that @a a equals @a b + * + * @a a and @a b will be converted to `void *` before comparing. + * + * @param a Value to compare + * @param b Value to compare + * @param msg Optional message to print if the assertion fails + */ +#define ast_zassert_equal_ptr(a, b, msg, ...) \ + ast_zassert((void *)(a) == (void *)(b), #a " not equal to " #b, \ + msg, ##__VA_ARGS__) + +/** + * @brief Assert that @a a is within @a b with delta @a d + * + * @param a Value to compare + * @param b Value to compare + * @param d Delta + * @param msg Optional message to print if the assertion fails + */ +#define ast_zassert_within(a, b, d, msg, ...) \ + ast_zassert(((a) >= ((b) - (d))) && ((a) <= ((b) + (d))), \ + #a " not within " #b " +/- " #d, \ + msg, ##__VA_ARGS__) + +/** + * @brief Assert that 2 memory buffers have the same contents + * + * This macro calls the final memory comparison assertion macro. + * Using double expansion allows providing some arguments by macros that + * would expand to more than one values (ANSI-C99 defines that all the macro + * arguments have to be expanded before macro call). + * + * @param ... Arguments, see @ref zassert_mem_equal__ + * for real arguments accepted. + */ +#define ast_zassert_mem_equal(...) \ + ast_zassert_mem_equal__(__VA_ARGS__) + +/** + * @brief Internal assert that 2 memory buffers have the same contents + * + * @note This is internal macro, to be used as a second expansion. + * See @ref zassert_mem_equal. + * + * @param buf Buffer to compare + * @param exp Buffer with expected contents + * @param size Size of buffers + * @param msg Optional message to print if the assertion fails + */ +#define ast_zassert_mem_equal__(buf, exp, size, msg, ...) \ + ast_zassert(memcmp(buf, exp, size) == 0, #buf " not equal to " #exp, \ + msg, ##__VA_ARGS__) + +#endif /* ZEPHYR_TESTSUITE_ZTEST_ASSERT_H_ */ diff --git a/tests/boards/npcm400f_evb/src/i3c.c b/tests/boards/npcm400f_evb/src/i3c.c new file mode 100644 index 00000000000000..ea5e3ce153de8d --- /dev/null +++ b/tests/boards/npcm400f_evb/src/i3c.c @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include "ast_test.h" + +#define LOG_MODULE_NAME i3c_test + +#include +LOG_MODULE_REGISTER(LOG_MODULE_NAME); + + +#define TEST_PRIV_XFER_SIZE 256 +#define TEST_IBI_PAYLOAD_SIZE 128 +#define MAX_DATA_SIZE 256 + +static uint8_t test_data_tx[MAX_DATA_SIZE]; +static uint8_t test_data_rx[MAX_DATA_SIZE]; + +/*#define TEST_LOOPBACK*/ +#define TEST_WITH_LSM6DSO +#define TEST_DBG + +static void test_i3c_ci(int count) +{ + const struct device *dev_master, *dev_slave; + const struct device *dev = NULL; + struct i3c_dev_desc *slave = NULL; + struct i3c_priv_xfer xfer[2]; + int ret, i; + +#if defined(TEST_LOOPBACK) + struct i3c_dev_desc slave_i3c; + + slave = &slave_i3c; +#elif defined(TEST_WITH_LSM6DSO) + struct i3c_dev_desc slave_lsm6dso; + + slave = &slave_lsm6dso; +#endif + + dev_master = device_get_binding(DT_LABEL(DT_NODELABEL(i3c0))); + dev_slave = device_get_binding(DT_LABEL(DT_NODELABEL(i3c1))); + + /* Not ready, do not use */ +#ifndef TEST_DBG + if (!device_is_ready(dev_master) || !device_is_ready(dev_slave)) + return; +#else + if (dev_master == NULL) { + dev = DEVICE_DT_GET(DT_NODELABEL(i3c0)); + if (dev == NULL) { + LOG_INF("I3C0 is not found in device tree !\n"); + return; + } + + if (!device_is_ready(dev)) { + if (dev->state->initialized == false) { + LOG_INF("I3C0 is found in device tree, but not init !\n"); + return; + } + + LOG_INF("I3C0 is initialized, but fail !\n"); + return; + } + } + + if (dev_slave == NULL) { + dev = DEVICE_DT_GET(DT_NODELABEL(i3c1)); + if (dev == NULL) { + LOG_INF("I3C1 is not found in device tree !\n"); + return; + } + + if (!device_is_ready(dev)) { + if (dev->state->initialized == false) { + LOG_INF("I3C1 is found in device tree, but not initialized !\n"); + return; + } + + LOG_INF("I3C1 is initialized, but fail !\n"); + return; + } + } +#endif + +#if defined(TEST_LOOPBACK) + slave->info.static_addr = DT_PROP(DT_NODELABEL(i3c1), assigned_address); + slave->info.assigned_dynamic_addr = slave->info.static_addr; + slave->info.i2c_mode = 1; /* default run i2c mode */ +#elif defined(TEST_WITH_LSM6DSO) + /* attach lsm6dso */ + #define LSM6DSO_ADDR 0x6B + slave->info.static_addr = LSM6DSO_ADDR; + slave->info.assigned_dynamic_addr = LSM6DSO_ADDR; + slave->info.i2c_mode = 1; +#endif + + if (slave == NULL) + return; + + i3c_master_attach_device(dev_master, slave); + i3c_master_send_rstdaa(dev_master); + + for (i = 0; i < count; i++) { + /* + * Test part 1: + * master --- i2c private write transfer ---> slave + */ + xfer[0].rnw = 0; + xfer[0].len = 1; + xfer[0].data.out = test_data_tx; + test_data_tx[0] = 0x0F; + + ret = i3c_master_priv_xfer(slave, xfer, 1); + + /* + * Test part 2: + * master --- i2c private read transfer ---> slave + */ + xfer[0].rnw = 1; + xfer[0].len = 1; + xfer[0].data.in = test_data_rx; + + ret = i3c_master_priv_xfer(slave, xfer, 1); + __ASSERT(test_data_rx[0] == 0x6C, "Read Data Fail !!!\n\n"); + + /* + * Test part 3: for those who support stopsplitread + * master --- i2c private write then read transfer ---> slave + */ + memset(test_data_rx, 0x00, sizeof(test_data_rx)); + + i3c_i2c_read(slave, 0x0F, test_data_rx, 1); + __ASSERT(test_data_rx[0] == 0x6C, "Read Data Fail !!!\n\n"); + + /* + * Test part 4: + * master --- i2c API ---> slave + */ + test_data_tx[0] = 0xC0; + ret = i3c_i2c_write(slave, 0x01, test_data_tx, 1); + ret = i3c_i2c_read(slave, 0x01, test_data_rx, 1); + __ASSERT(test_data_rx[0] == 0xC0, "Read Data Fail !!!\n\n"); + + test_data_tx[0] = 0x00; + ret = i3c_i2c_write(slave, 0x01, test_data_tx, 1); + ret = i3c_i2c_read(slave, 0x01, test_data_rx, 1); + __ASSERT(test_data_rx[0] == 0x00, "Read Data Fail !!!\n\n"); + } + + i3c_master_send_entdaa(slave); + /* i3c_master_send_aasa(master); */ + slave->info.i2c_mode = 0; + + i3c_master_send_getpid(dev_master, slave->info.dynamic_addr, &slave->info.pid); + i3c_master_send_getbcr(dev_master, slave->info.dynamic_addr, &slave->info.bcr); + + for (i = 0; i < count; i++) { + /* + * Test part 1: + * master --- i3c private write transfer ---> slave + */ + xfer[0].rnw = 0; + xfer[0].len = 1; + xfer[0].data.out = test_data_tx; + test_data_tx[0] = 0x0F; + ret = i3c_master_priv_xfer(slave, xfer, 1); + + /* + * Test part 2: + * master --- i3c private read transfer ---> slave + */ + xfer[0].rnw = 1; + xfer[0].len = 1; + xfer[0].data.in = test_data_rx; + + ret = i3c_master_priv_xfer(slave, xfer, 1); + __ASSERT(test_data_rx[0] == 0x6C, "Read Data Fail !!!\n\n"); + + /* + * Test part 3: for those who support stopsplitread + * master --- i3c private write then read transfer ---> slave + */ + memset(test_data_rx, 0x00, sizeof(test_data_rx)); + + test_data_tx[0] = 0x0F; /* WHO_AM_I, lsm6dso */ + ret = i3c_jesd403_read(slave, test_data_tx, 1, test_data_rx, 1); + __ASSERT(test_data_rx[0] == 0x6C, "Read Data Fail !!!\n\n"); + + /* + * Test part 4: + * master --- i3c API ---> slave + */ + memset(test_data_rx, 0x00, sizeof(test_data_rx)); + test_data_tx[0] = 0x01; + test_data_tx[1] = 0xC0; + ret = i3c_jesd403_write(slave, test_data_tx, 1, &test_data_tx[1], 1); + ret = i3c_jesd403_read(slave, test_data_tx, 1, test_data_rx, 1); + __ASSERT(test_data_rx[0] == 0xC0, "Read Data Fail !!!\n\n"); + + test_data_tx[1] = 0x00; + ret = i3c_jesd403_write(slave, test_data_tx, 1, &test_data_tx[1], 1); + ret = i3c_jesd403_read(slave, test_data_tx, 1, test_data_rx, 1); + __ASSERT(test_data_rx[0] == 0x00, "Read Data Fail !!!\n\n"); + + /* + * Test part 2: + * if MDB group ID is pending read notification: + * master <--- IBI notification --------- slave + * master ---- private read transfer ---> slave + * else: + * master <--- IBI with data --------- slave + */ + } +} + +int test_i3c(int count, enum aspeed_test_type type) +{ + printk("%s, count: %d, type: %d\n", __func__, count, type); + + if (type == AST_TEST_CI) { + test_i3c_ci(count); + return ast_ztest_result(); + } + + /* Not support FT yet */ + return AST_TEST_PASS; +} diff --git a/tests/boards/npcm400f_evb/src/main.c b/tests/boards/npcm400f_evb/src/main.c new file mode 100644 index 00000000000000..bc3868e5c4b350 --- /dev/null +++ b/tests/boards/npcm400f_evb/src/main.c @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "ast_test.h" + +#define LOG_MODULE_NAME aspeed_test + +#include +LOG_MODULE_REGISTER(LOG_MODULE_NAME); + +extern void test_i3c(void); + +#define run_test_suite(suite, type) \ + nuvoton_run_test_suite(#suite, _##suite, type) + +#define TEST_MODULE_CNT 1 +#define TEST_STACKSIZE 4096 + +#define TEST_CI_TIMEOUT 40 +#define TEST_SLT_TIMEOUT 20 +#define TEST_FT_TIMEOUT 5 + +#define TEST_CI_FUNC_COUNT 1 +#define TEST_SLT_FUNC_COUNT 1 +#define TEST_FT_FUNC_COUNT 1 + +K_THREAD_STACK_ARRAY_DEFINE(test_thread_stack, TEST_MODULE_CNT, TEST_STACKSIZE); + +static struct aspeed_test_param test_params[] = { + { AST_TEST_CI, "AST_TEST_CI", TEST_CI_FUNC_COUNT, TEST_CI_TIMEOUT }, + { AST_TEST_SLT, "AST_TEST_SLT", TEST_SLT_FUNC_COUNT, TEST_SLT_TIMEOUT }, + { AST_TEST_FT, "AST_TEST_FT", TEST_FT_FUNC_COUNT, TEST_FT_TIMEOUT }, +}; + +typedef int (*test_func_t) (int count, enum aspeed_test_type); + +static struct aspeed_tests aspeed_testcase[TEST_MODULE_CNT]; +static struct k_thread ztest_thread[TEST_MODULE_CNT]; +static int unit_test_count; +static int unit_test_remain; + +static void aspeed_pre_init(void) +{ +#if CONFIG_BOARD_AST1030_FT + aspeed_ft_pre_init(); +#endif +} + +static void aspeed_post_init(void) +{ +#if CONFIG_BOARD_AST1030_FT + aspeed_ft_post_init(aspeed_testcase, TEST_MODULE_CNT); +#endif +} + +static void aspeed_test_cb(void *a, void *b, void *c) +{ + int num = (int)a; + int count = (int)b; + enum aspeed_test_type type = (enum aspeed_test_type)c; + int ret = TC_FAIL; + + TC_START(aspeed_testcase[num].name); + + LOG_DBG("Current thread id: %d", (int)k_current_get()); + ret = aspeed_testcase[num].test(count, type); + aspeed_testcase[num].results = ret; + + unit_test_remain--; + Z_TC_END_RESULT(ret, aspeed_testcase[num].name); +} + +static int nuvoton_create_test(struct unit_test *test, int thread_num, + int count, enum aspeed_test_type type) +{ + int ret = TC_PASS; + k_tid_t pid; + + if (IS_ENABLED(CONFIG_MULTITHREADING)) { + pid = k_thread_create(&ztest_thread[thread_num], + test_thread_stack[thread_num], + TEST_STACKSIZE, + (k_thread_entry_t) aspeed_test_cb, + (void *)thread_num, + (void *)count, (void *)type, + CONFIG_ZTEST_THREAD_PRIORITY, + test->thread_options | K_INHERIT_PERMS, + K_FOREVER); + + if (test->name != NULL) { + k_thread_name_set(&ztest_thread[thread_num], + test->name); + } + + } else { + LOG_ERR("multithreading is not supported"); + ret = TC_FAIL; + } + + aspeed_testcase[thread_num].name = test->name; + aspeed_testcase[thread_num].test = (test_func_t) test->test; + aspeed_testcase[thread_num].results = -1; + + LOG_INF("Create thread %s\t to num %d, pid: %d", + test->name, thread_num, (int)pid); + + return ret; +} + +static void nuvoton_run_test(void) +{ + int i; + + for (i = 0; i < unit_test_count; i++) { + k_thread_start(&ztest_thread[i]); + } +} + +static void aspeed_show_banner(bool is_passed) +{ + if (is_passed) { + LOG_ERR("\x1b[;32;1m\n" + "######## ### ###### ###### ######## ########\n" + "## ## ## ## ## ## ## ## ## ## ##\n" + "## ## ## ## ## ## ## ## ##\n" + "######## ## ## ###### ###### ###### ## ##\n" + "## ######### ## ## ## ## ##\n" + "## ## ## ## ## ## ## ## ## ##\n" + "## ## ## ###### ###### ######## ########\n" + "\x1b[0;m\n" + ); + } else { + LOG_ERR("\x1b[;31;1m\n" + "######## ### #### ## ######## ########\n" + "## ## ## ## ## ## ## ##\n" + "## ## ## ## ## ## ## ##\n" + "###### ## ## ## ## ###### ## ##\n" + "## ######### ## ## ## ## ##\n" + "## ## ## ## ## ## ## ##\n" + "## ## ## #### ######## ######## ########\n" + "\x1b[0;m\n" + ); + } +} + +static void aspeed_terminate_test(int type) +{ + bool is_passed = true; + int i; + + LOG_INF("\nTest Counter: %d. Test Type: %s.", + test_params[type].test_count, + test_params[type].name); + + for (i = 0; i < unit_test_count; i++) { + k_thread_abort(&ztest_thread[i]); + if (aspeed_testcase[i].results) + is_passed = false; + + LOG_INF("Case %d - %s results: %s", i + 1, + aspeed_testcase[i].name, + aspeed_testcase[i].results ? "FAILED" : "PASSED"); + } + + aspeed_show_banner(is_passed); + zassert_equal(is_passed, true, "%s FAILED"); +} + +static void nuvoton_run_test_suite(const char *name, struct unit_test *suite, + int type) +{ + int timer = 0; + int fail = 0; + + aspeed_pre_init(); + + while (suite->test) { + fail += nuvoton_create_test(suite, unit_test_count++, + test_params[type].test_count, type); + suite++; + if (unit_test_count >= TEST_MODULE_CNT) { + LOG_ERR("unit test numbers are limited to %d\n", + unit_test_count); + break; + } + } + + if (fail) + goto end; + + unit_test_remain = unit_test_count; + thread_analyzer_print(); + + nuvoton_run_test(); + + while (unit_test_remain && (timer < test_params[type].timeout)) { + timer++; + k_sleep(K_SECONDS(1)); + } + + if (unit_test_remain) { + LOG_ERR("TIMEOUT ! Total test case: %d, remaining: %d", + unit_test_count, unit_test_remain); + fail++; + } + +end: + aspeed_post_init(); + aspeed_terminate_test(type); + zassert_equal(fail, 0, "test ast1030 failed"); +} + +static void nuvoton_test_platform(void) +{ + ztest_test_suite(test_npcm400f, + ztest_unit_test(test_i3c) + ); + + run_test_suite(test_npcm400f, AST_TEST_CI); +} + +/* test case main entry */ +void test_main(void) +{ + ztest_test_suite(platform_test, + ztest_unit_test(nuvoton_test_platform)); + + ztest_run_test_suite(platform_test); +}