From b9ebe7b6ace1e0b7771a859e9dea976818ce6c54 Mon Sep 17 00:00:00 2001 From: James Chiang Date: Mon, 9 Sep 2024 22:26:42 -0700 Subject: [PATCH 1/5] drivers: i3c: add npcm4xx i3c reset function add npcm4xx i3c reset function. Signed-off-by: James Chiang --- drivers/i3c/i3c_npcm4xx.c | 38 ++++++++++++++++++++++++++- drivers/i3c/npcm4xx/i3c_drv.h | 2 ++ dts/arm/nuvoton/npcm400f.dtsi | 24 ++++++++++++----- soc/arm/npcm4xx/common/reg/reg_def.h | 39 +++++++++++++++++++++------- 4 files changed, 86 insertions(+), 17 deletions(-) diff --git a/drivers/i3c/i3c_npcm4xx.c b/drivers/i3c/i3c_npcm4xx.c index c2ead24951912f..6c01443397327b 100644 --- a/drivers/i3c/i3c_npcm4xx.c +++ b/drivers/i3c/i3c_npcm4xx.c @@ -1745,6 +1745,40 @@ I3C_ErrCode_Enum hal_I3C_Stop(I3C_PORT_Enum port) return I3C_ERR_OK; } +static void i3c_npcm4xx_reset(I3C_PORT_Enum port) +{ + struct i3c_npcm4xx_obj *obj; + struct i3c_npcm4xx_config *config; + struct pmc_reg *pmc_base; + uint8_t sw_rst; + + obj = gObj[port]; + config = obj->config; + + /* disable i3c interrupt */ + irq_disable(config->irq); + + pmc_base = (struct pmc_reg *)config->pmc_base; + + /* save reset value */ + sw_rst = pmc_base->SW_RST1; + + /* trigger sw reset */ + pmc_base->SW_RST1 = (sw_rst | BIT(port)); + + /* after reset done, partno become zero */ + while(I3C_GET_REG_PARTNO(port)); + + /* restore reset value */ + pmc_base->SW_RST1 = sw_rst; + + /* re-init device configuration */ + hal_I3C_Config_Device(api_I3C_Get_INODE(port)); + + /* enable irq interrupt */ + irq_enable(config->irq); +} + I3C_ErrCode_Enum hal_I3C_Start_IBI(I3C_TASK_INFO_t *pTaskInfo) { I3C_PORT_Enum port; @@ -4452,7 +4486,9 @@ static int i3c_npcm4xx_init(const struct device *dev) .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),\ + .base = (struct i3c_reg *)DT_INST_REG_ADDR_BY_NAME(n, i3c),\ + .pmc_base = DT_INST_REG_ADDR_BY_NAME(n, pmc),\ + .irq = DT_INST_IRQN(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,\ diff --git a/drivers/i3c/npcm4xx/i3c_drv.h b/drivers/i3c/npcm4xx/i3c_drv.h index 263b58b43b7606..9d2464b7352d5a 100644 --- a/drivers/i3c/npcm4xx/i3c_drv.h +++ b/drivers/i3c/npcm4xx/i3c_drv.h @@ -94,6 +94,8 @@ struct i3c_npcm4xx_config { int dma_tx_channel; int dma_rx_channel; struct i3c_reg *base; + uintptr_t pmc_base; + uint32_t irq; bool slave; bool secondary; uint32_t i3c_scl_hz; diff --git a/dts/arm/nuvoton/npcm400f.dtsi b/dts/arm/nuvoton/npcm400f.dtsi index 49b08315c1b986..cef0e1cda8a807 100644 --- a/dts/arm/nuvoton/npcm400f.dtsi +++ b/dts/arm/nuvoton/npcm400f.dtsi @@ -173,7 +173,9 @@ compatible = "nuvoton,npcm4xx-i3c"; #address-cells = <1>; #size-cells = <0>; - reg = <0x40004000 0x200>; + reg = <0x40004000 0x200 + 0x4000d000 0x20>; + reg-names = "i3c", "pmc"; interrupts = <64 3>; instance-id = <0>; status = "disabled"; @@ -184,7 +186,9 @@ compatible = "nuvoton,npcm4xx-i3c"; #address-cells = <1>; #size-cells = <0>; - reg = <0x40004200 0x200>; + reg = <0x40004200 0x200 + 0x4000d000 0x20>; + reg-names = "i3c", "pmc"; interrupts = <65 3>; instance-id = <1>; status = "disabled"; @@ -195,7 +199,9 @@ compatible = "nuvoton,npcm4xx-i3c"; #address-cells = <1>; #size-cells = <0>; - reg = <0x40004400 0x200>; + reg = <0x40004400 0x200 + 0x4000d000 0x20>; + reg-names = "i3c", "pmc"; interrupts = <66 3>; instance-id = <2>; status = "disabled"; @@ -206,7 +212,9 @@ compatible = "nuvoton,npcm4xx-i3c"; #address-cells = <1>; #size-cells = <0>; - reg = <0x40004600 0x200>; + reg = <0x40004600 0x200 + 0x4000d000 0x20>; + reg-names = "i3c", "pmc"; interrupts = <67 3>; instance-id = <3>; status = "disabled"; @@ -217,7 +225,9 @@ compatible = "nuvoton,npcm4xx-i3c"; #address-cells = <1>; #size-cells = <0>; - reg = <0x40004800 0x200>; + reg = <0x40004800 0x200 + 0x4000d000 0x20>; + reg-names = "i3c", "pmc"; interrupts = <68 3>; instance-id = <4>; status = "disabled"; @@ -228,7 +238,9 @@ compatible = "nuvoton,npcm4xx-i3c"; #address-cells = <1>; #size-cells = <0>; - reg = <0x40004a00 0x200>; + reg = <0x40004a00 0x200 + 0x4000d000 0x20>; + reg-names = "i3c", "pmc"; interrupts = <69 3>; instance-id = <5>; status = "disabled"; diff --git a/soc/arm/npcm4xx/common/reg/reg_def.h b/soc/arm/npcm4xx/common/reg/reg_def.h index f33e280a048ed0..a1f906d36f2281 100644 --- a/soc/arm/npcm4xx/common/reg/reg_def.h +++ b/soc/arm/npcm4xx/common/reg/reg_def.h @@ -116,19 +116,38 @@ struct pmc_reg { volatile uint8_t DISIDL_CTL; /* 0x005: Disable in Idle Control 1 */ volatile uint8_t DISIDL_CTL1; - volatile uint8_t reserved2[2]; - /* 0x008 - 0D: Power-Down Control 1 - 6 */ - volatile uint8_t PWDWN_CTL1[6]; - volatile uint8_t reserved3[18]; - /* 0x020 - 21: Power-Down Control 1 - 2 */ - volatile uint8_t RAM_PD[2]; - volatile uint8_t reserved4[2]; - /* 0x024: Power-Down Control 7 */ - volatile uint8_t PWDWN_CTL7[1]; + volatile uint8_t reserved2; + /* 0x007: Power-Down Control 0 */ + volatile uint8_t PWDWN_CTL0; + /* 0x008: Power-Down Control 1 */ + volatile uint8_t PWDWN_CTL1; + /* 0x009: Power-Down Control 2 */ + volatile uint8_t PWDWN_CTL2; + /* 0x00A: Power-Down Control 3 */ + volatile uint8_t PWDWN_CTL3; + /* 0x00B: Power-Down Control 4 */ + volatile uint8_t PWDWN_CTL4; + /* 0x00C: Power-Down Control 5 */ + volatile uint8_t PWDWN_CTL5; + /* 0x00D: Power-Down Control 6 */ + volatile uint8_t PWDWN_CTL6; + volatile uint8_t reserved3[3]; + /* 0x011: RAM Power-Down Control 1 */ + volatile uint8_t RAM_PD1; + /* 0x012: RAM Power-Down Control 2 */ + volatile uint8_t RAM_PD2; + /* 0x013: Software Reset 1 */ + volatile uint8_t SW_RST1; + /* 0x014: RAM Power-Down Control 3 */ + volatile uint8_t RAM_PD3; + /* 0x015: Power-Down Control 7 */ + volatile uint8_t PWDWN_CTL7; + /* 0x016: Power-Down Control 8 */ + volatile uint8_t PWDWN_CTL8; }; /* PMC multi-registers */ -#define NPCM4XX_PWDWN_CTL_OFFSET(n) (((n) < 7) ? (0x007 + n) : (0x024 + (n - 7))) +#define NPCM4XX_PWDWN_CTL_OFFSET(n) (((n) < 7) ? (0x007 + n) : (0x015 + (n - 7))) #define NPCM4XX_PWDWN_CTL(base, n) (*(volatile uint8_t *)(base + \ NPCM4XX_PWDWN_CTL_OFFSET(n))) From 1fdd9c1224ac2c09e2bcccb9df306feaa144fb18 Mon Sep 17 00:00:00 2001 From: James Chiang Date: Mon, 9 Sep 2024 23:44:54 -0700 Subject: [PATCH 2/5] drivers: i3c: enhance i3c hot-join request flow enhance i3c hot-join request flow. i3c hw fail to generate hot-join event when bus is not in the idle status, and the fail would lead hw into stuck state. (1) check dynamic address present or not before generate hot-join event. (2) check entdaa progress before generate hot-join event. (3) after wait util bus idle, check dynamic address present or not. (4) remove disable slave mode since hot-join event could generate even if slave mode enabled. (5) if ctrl keep hot-join event for a while, check dynamic address present or not. (6) reset i3c controller after timeout and retry generate hot-join event. Signed-off-by: James Chiang --- drivers/i3c/i3c_npcm4xx.c | 150 +++++++++++++++++++++++++++++++++++--- 1 file changed, 139 insertions(+), 11 deletions(-) diff --git a/drivers/i3c/i3c_npcm4xx.c b/drivers/i3c/i3c_npcm4xx.c index 6c01443397327b..0a33e39426c7f3 100644 --- a/drivers/i3c/i3c_npcm4xx.c +++ b/drivers/i3c/i3c_npcm4xx.c @@ -34,6 +34,9 @@ static struct i3c_npcm4xx_obj *gObj[I3C_PORT_MAX]; #define NPCM4XX_I3C_WORK_QUEUE_STACK_SIZE 1024 #define NPCM4XX_I3C_WORK_QUEUE_PRIORITY -2 +#define NPCM4XX_I3C_HJ_RETRY_MAX 0x5 +#define NPCM4XX_I3C_HJ_CHECK_MAX 0x3 + #if DT_NODE_HAS_STATUS(DT_NODELABEL(i3c0), okay) K_THREAD_STACK_DEFINE(npcm4xx_i3c_stack_area0, NPCM4XX_I3C_WORK_QUEUE_STACK_SIZE); #endif @@ -1826,7 +1829,7 @@ I3C_ErrCode_Enum hal_I3C_Start_IBI(I3C_TASK_INFO_t *pTaskInfo) } } - ctrl |= I3C_CTRL_EVENT(1); + ctrl |= I3C_CTRL_EVENT(I3C_CTRL_EVENT_IBI); I3C_SET_REG_CTRL(port, ctrl); return I3C_ERR_OK; @@ -1862,7 +1865,7 @@ I3C_ErrCode_Enum hal_I3C_Start_Master_Request(I3C_TASK_INFO_t *pTaskInfo) pDevice->rxOffset = 0; ctrl = I3C_GET_REG_CTRL(port); - ctrl |= I3C_CTRL_EVENT(2); + ctrl |= I3C_CTRL_EVENT(I3C_CTRL_EVENT_MstReq); I3C_SET_REG_CTRL(port, ctrl); return I3C_ERR_OK; } @@ -1871,20 +1874,60 @@ I3C_ErrCode_Enum hal_I3C_Start_HotJoin(I3C_TASK_INFO_t *pTaskInfo) { I3C_PORT_Enum port; I3C_DEVICE_INFO_t *pDevice; + I3C_TRANSFER_TASK_t *pTask; + I3C_ErrCode_Enum ret = I3C_ERR_OK; + struct i3c_npcm4xx_obj *obj; __u8 pdma_ch; uint32_t ctrl; + uint8_t retry; + uint8_t check_count; - if (pTaskInfo == NULL) - return I3C_ERR_PARAMETER_INVALID; + if (pTaskInfo == NULL) { + LOG_ERR("HotJoin: pTaskInfo NULL\n"); + ret = I3C_ERR_PARAMETER_INVALID; + goto hj_exit; + } port = pTaskInfo->Port; - if (port >= I3C_PORT_MAX) - return I3C_ERR_PARAMETER_INVALID; + if (port >= I3C_PORT_MAX) { + LOG_ERR("HotJoin: Port not valid = 0x%x\n", port); + ret = I3C_ERR_PARAMETER_INVALID; + goto hj_exit; + } + + obj = gObj[port]; + + pTask = pTaskInfo->pTask; + + /* check dynamic address already present or not */ + if (I3C_Update_Dynamic_Address(port)) { + LOG_WRN("HotJoin: DA present before generate Hot-Join\n"); + if (pTask) { + api_I3C_Slave_End_Request((uint32_t)pTask); + } + + ret = I3C_ERR_OK; + goto hj_exit; + } + + /* check daa is under progress or not */ + if (I3C_GET_REG_STATUS(port) & I3C_STATUS_STDAA_MASK) { + LOG_WRN("HotJoin: STDAA work in progress.\n"); + if (pTask) { + api_I3C_Slave_End_Request((uint32_t)pTask); + } + + ret = I3C_ERR_OK; + goto hj_exit; + } 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; + ((pDevice->mode != I3C_DEVICE_MODE_SECONDARY_MASTER))) { + LOG_ERR("HotJoin: Only support slave or secondary master\n"); + ret = I3C_ERR_PARAMETER_INVALID; + goto hj_exit; + } pdma_ch = Get_PDMA_Channel(port, I3C_TRANSFER_DIR_WRITE); PDMA->CHCTL &= ~MaskBit(PDMA_OFFSET + pdma_ch); @@ -1898,12 +1941,88 @@ I3C_ErrCode_Enum hal_I3C_Start_HotJoin(I3C_TASK_INFO_t *pTaskInfo) ctrl = I3C_GET_REG_CTRL(port); ctrl &= ~(I3C_CTRL_IBIDATA_MASK | I3C_CTRL_EXTDATA_MASK | I3C_CTRL_EVENT_MASK); - ctrl |= I3C_CTRL_EVENT(3); + ctrl |= I3C_CTRL_EVENT(I3C_CTRL_EVENT_HotJoin); + + /* initial retry and check count */ + retry = 0x0; + check_count = 0x0; + +hj_retry: + /* wait util bus idle */ + while(I3C_GET_REG_STATUS(port) & I3C_STATUS_STNOTSTOP_MASK); + + /* if daa already done, exit hot-join progress */ + if (I3C_Update_Dynamic_Address(port)) { + LOG_WRN("HotJoin: Bus BUS idle and DA present\n"); + if (pTask) { + api_I3C_Slave_End_Request((uint32_t)pTask); + } + + ret = I3C_ERR_OK; + goto hj_exit; + } - I3C_SET_REG_CONFIG(port, I3C_GET_REG_CONFIG(port) & ~I3C_CONFIG_SLVENA_MASK); + /* HotJoin only could generate when bus idle, otherwise hw may stuck. */ I3C_SET_REG_CTRL(port, ctrl); I3C_SET_REG_CONFIG(port, I3C_GET_REG_CONFIG(port) | I3C_CONFIG_SLVENA_MASK); - return I3C_ERR_OK; + + do { + /* wait 1ms */ + k_busy_wait(1000); + + if ((I3C_GET_REG_CTRL(port) & I3C_CTRL_EVENT_MASK) == + I3C_CTRL_EVENT_None) { + LOG_WRN("HotJoin: Send successful\n"); + ret = I3C_ERR_OK; + goto hj_exit; + } else { + check_count++; + } + + if (check_count >= NPCM4XX_I3C_HJ_CHECK_MAX) + break; + + } while(true); + + if (I3C_Update_Dynamic_Address(port)) { + LOG_WRN("HotJoin: Try to generate event but DA=0x%x present\n", + I3C_Update_Dynamic_Address(port)); + + /* Disable generate event */ + I3C_SET_REG_CTRL(port, I3C_CTRL_EVENT_None); + + if (pTask) { + api_I3C_Slave_End_Request((uint32_t)pTask); + } + + ret = I3C_ERR_OK; + goto hj_exit; + } + + /* reset i3c hw since there is no dynamic address present */ + i3c_npcm4xx_reset(port); + + /* add retry count */ + retry++; + + if (retry >= NPCM4XX_I3C_HJ_RETRY_MAX) { + LOG_ERR("HotJoin: Send event failed\n"); + if (pTask) { + api_I3C_Slave_End_Request((uint32_t)pTask); + } + + ret = I3C_ERR_BUS_ERROR; + goto hj_exit; + } else { + /* re-initial check count */ + check_count = 0x0; + /* retry again */ + goto hj_retry; + } + +hj_exit: + + return ret; } I3C_ErrCode_Enum hal_I3C_Slave_TX_Free(I3C_PORT_Enum port) @@ -2641,8 +2760,17 @@ int i3c_npcm4xx_slave_hj_req(const struct device *dev) { struct i3c_npcm4xx_config *config = DEV_CFG(dev); I3C_PORT_Enum port; + uint8_t addr; port = config->inst_id; + + addr = I3C_Update_Dynamic_Address((uint32_t) port); + + if (addr) { + LOG_ERR("Dynamic address present = 0x%x\n", addr); + return -1; + } + I3C_Slave_Insert_Task_HotJoin(port); k_work_submit_to_queue(&npcm4xx_i3c_work_q[port], &work_send_ibi[port]); From 6d44688e0883d8825ecbf40020d8c03054c294f9 Mon Sep 17 00:00:00 2001 From: James Chiang Date: Tue, 10 Sep 2024 19:48:03 -0700 Subject: [PATCH 3/5] drivers: i3c: support auto hot-join request support auto hot-join request. use software to simulate auto hot-join flow. (1) system power up, monitor bus status in interrupt, and generate hot-join event when received stop message. (2) watchdog or software reset, generate hot-join event immediately. Signed-off-by: James Chiang --- drivers/i3c/i3c_npcm4xx.c | 143 ++++++++++++++++++++++------ drivers/i3c/npcm4xx/i3c_drv.h | 9 ++ soc/arm/npcm4xx/common/soc_common.h | 5 + 3 files changed, 127 insertions(+), 30 deletions(-) diff --git a/drivers/i3c/i3c_npcm4xx.c b/drivers/i3c/i3c_npcm4xx.c index 0a33e39426c7f3..697a880f96cd2d 100644 --- a/drivers/i3c/i3c_npcm4xx.c +++ b/drivers/i3c/i3c_npcm4xx.c @@ -34,8 +34,10 @@ static struct i3c_npcm4xx_obj *gObj[I3C_PORT_MAX]; #define NPCM4XX_I3C_WORK_QUEUE_STACK_SIZE 1024 #define NPCM4XX_I3C_WORK_QUEUE_PRIORITY -2 -#define NPCM4XX_I3C_HJ_RETRY_MAX 0x5 -#define NPCM4XX_I3C_HJ_CHECK_MAX 0x3 +/* current set 10ms * 5 * 3 => 0.15 seconds */ +#define NPCM4XX_I3C_HJ_RETRY_MAX 3 +#define NPCM4XX_I3C_HJ_CHECK_MAX 5 +#define NPCM4XX_I3C_HJ_UDELAY 10000 #if DT_NODE_HAS_STATUS(DT_NODELABEL(i3c0), okay) K_THREAD_STACK_DEFINE(npcm4xx_i3c_stack_area0, NPCM4XX_I3C_WORK_QUEUE_STACK_SIZE); @@ -581,6 +583,7 @@ 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; + struct i3c_npcm4xx_obj *obj; uint32_t mconfig; uint32_t sconfig; @@ -709,8 +712,10 @@ I3C_ErrCode_Enum hal_I3C_Config_Device(I3C_DEVICE_INFO_t *pDevice) sconfig |= I3C_CONFIG_SADDR(pDevice->staticAddr); sconfig &= ~I3C_CONFIG_S0IGNORE_MASK; - /* sconfig &= ~I3C_CONFIG_MATCHSS_MASK; */ - sconfig |= I3C_CONFIG_MATCHSS_MASK; + + obj = gObj[port]; + + sconfig &= ~I3C_CONFIG_MATCHSS_MASK; sconfig &= ~I3C_CONFIG_NACK_MASK; /* 0: Fixed, 1: Random */ @@ -1876,7 +1881,7 @@ I3C_ErrCode_Enum hal_I3C_Start_HotJoin(I3C_TASK_INFO_t *pTaskInfo) I3C_DEVICE_INFO_t *pDevice; I3C_TRANSFER_TASK_t *pTask; I3C_ErrCode_Enum ret = I3C_ERR_OK; - struct i3c_npcm4xx_obj *obj; + struct i3c_npcm4xx_obj *obj = NULL; __u8 pdma_ch; uint32_t ctrl; uint8_t retry; @@ -1967,8 +1972,7 @@ I3C_ErrCode_Enum hal_I3C_Start_HotJoin(I3C_TASK_INFO_t *pTaskInfo) I3C_SET_REG_CONFIG(port, I3C_GET_REG_CONFIG(port) | I3C_CONFIG_SLVENA_MASK); do { - /* wait 1ms */ - k_busy_wait(1000); + k_busy_wait(NPCM4XX_I3C_HJ_UDELAY); if ((I3C_GET_REG_CTRL(port) & I3C_CTRL_EVENT_MASK) == I3C_CTRL_EVENT_None) { @@ -2021,6 +2025,9 @@ I3C_ErrCode_Enum hal_I3C_Start_HotJoin(I3C_TASK_INFO_t *pTaskInfo) } hj_exit: + if (obj) { + obj->config->hj_req = I3C_HOT_JOIN_STATE_None; + } return ret; } @@ -2771,9 +2778,21 @@ int i3c_npcm4xx_slave_hj_req(const struct device *dev) return -1; } - I3C_Slave_Insert_Task_HotJoin(port); - - k_work_submit_to_queue(&npcm4xx_i3c_work_q[port], &work_send_ibi[port]); + if (config->hj_req == I3C_HOT_JOIN_STATE_None) { + if (config->rst_reason == NPCM4XX_RESET_REASON_VCC_POWERUP) { + LOG_WRN("Auto Hot-Join\n"); + config->hj_req = I3C_HOT_JOIN_STATE_Request; + /* change reset reason to sw-rst, direct hot-join next time */ + config->rst_reason = NPCM4XX_RESET_REASON_DEBUGGER_RST; + } else { + LOG_WRN("Direct Hot-Join\n"); + I3C_Slave_Insert_Task_HotJoin(port); + k_work_submit_to_queue(&npcm4xx_i3c_work_q[port], &work_send_ibi[port]); + config->hj_req = I3C_HOT_JOIN_STATE_Queue; + } + } else { + LOG_WRN("Hot-Join request progress, state = %d\n", config->hj_req); + } return 0; } @@ -3801,12 +3820,15 @@ void I3C_Slave_ISR(uint8_t I3C_IF) I3C_TASK_INFO_t *pTaskInfo = NULL; I3C_TRANSFER_TASK_t *pTask; I3C_TRANSFER_FRAME_t *pFrame; + struct i3c_npcm4xx_obj *obj; uint32_t intmasked; uint32_t status; uint32_t ctrl; uint8_t evdet; uint32_t errwarn; bool bMATCHSS; + uint8_t addr; + uint32_t sconfig; ENTER_SLAVE_ISR(); @@ -3821,6 +3843,30 @@ void I3C_Slave_ISR(uint8_t I3C_IF) pDevice = api_I3C_Get_INODE(I3C_IF); + obj = gObj[I3C_IF]; + + if (bMATCHSS == false) { + if (obj->config->hj_req == I3C_HOT_JOIN_STATE_Request) { + if (intmasked & I3C_INTMASKED_STOP_MASK) { + I3C_Slave_Insert_Task_HotJoin(I3C_IF); + k_work_submit_to_queue(&npcm4xx_i3c_work_q[I3C_IF], + &work_send_ibi[I3C_IF]); + obj->config->hj_req = I3C_HOT_JOIN_STATE_Queue; + } + } + + if (status & I3C_STATUS_MATCHED_MASK) { + LOG_WRN("Status matched before set MATCHSS, set bMATCHSS as true\n"); + bMATCHSS = true; + } + } else { + if (obj->config->hj_req != I3C_HOT_JOIN_STATE_None) { + LOG_WRN("MATCHSS set. DA=0x%x\n", + I3C_Update_Dynamic_Address((uint32_t) I3C_IF)); + obj->config->hj_req = I3C_HOT_JOIN_STATE_None; + } + } + if (bMATCHSS && (intmasked & I3C_INTMASKED_EVENT_MASK)) { evdet = (uint8_t)((status & I3C_STATUS_EVDET_MASK) >> I3C_STATUS_EVDET_SHIFT); @@ -3843,6 +3889,14 @@ void I3C_Slave_ISR(uint8_t I3C_IF) api_I3C_Slave_End_Request((uint32_t)pTask); } + intmasked &= ~I3C_INTMASKED_EVENT_MASK; + if (!intmasked) { + EXIT_SLAVE_ISR(); + return; + } + } else if (intmasked & I3C_INTMASKED_EVENT_MASK){ + I3C_SET_REG_STATUS(I3C_IF, I3C_STATUS_EVENT_MASK); + intmasked &= ~I3C_INTMASKED_EVENT_MASK; if (!intmasked) { EXIT_SLAVE_ISR(); @@ -3852,16 +3906,22 @@ void I3C_Slave_ISR(uint8_t I3C_IF) if (intmasked & I3C_INTMASKED_DACHG_MASK) { /* LOG_INF("dynamic address changed\n"); */ - uint8_t addr; - struct i3c_npcm4xx_obj *obj; addr = I3C_Update_Dynamic_Address((uint32_t) I3C_IF); - obj = gObj[I3C_IF]; + sconfig = I3C_GET_REG_CONFIG(I3C_IF); if (addr) { obj->sir_allowed_by_sw = 1; LOG_WRN("dyn addr = %X\n", addr); + if (!(sconfig & I3C_CONFIG_MATCHSS_MASK)) { + sconfig |= I3C_CONFIG_MATCHSS_MASK; + I3C_SET_REG_CONFIG(I3C_IF, sconfig); + } } else { obj->sir_allowed_by_sw = 0; LOG_WRN("reset dyn addr\n"); + if (sconfig & I3C_CONFIG_MATCHSS_MASK) { + sconfig &= ~I3C_CONFIG_MATCHSS_MASK; + I3C_SET_REG_CONFIG(I3C_IF, sconfig); + } } I3C_SET_REG_STATUS(I3C_IF, I3C_STATUS_DACHG_MASK); @@ -3953,6 +4013,14 @@ void I3C_Slave_ISR(uint8_t I3C_IF) } } + intmasked &= ~I3C_INTMASKED_CHANDLED_MASK; + if (!intmasked) { + EXIT_SLAVE_ISR(); + return; + } + } else if (intmasked & I3C_INTMASKED_CHANDLED_MASK){ + I3C_SET_REG_STATUS(I3C_IF, I3C_STATUS_CHANDLED_MASK); + intmasked &= ~I3C_INTMASKED_CHANDLED_MASK; if (!intmasked) { EXIT_SLAVE_ISR(); @@ -3965,6 +4033,13 @@ void I3C_Slave_ISR(uint8_t I3C_IF) I3C_SET_REG_STATUS(I3C_IF, I3C_STATUS_DDRMATCH_MASK); + if (!intmasked) { + EXIT_SLAVE_ISR(); + return; + } + } else if (intmasked & I3C_INTMASKED_DDRMATCHED_MASK){ + I3C_SET_REG_STATUS(I3C_IF, I3C_STATUS_DDRMATCH_MASK); + if (!intmasked) { EXIT_SLAVE_ISR(); return; @@ -4053,23 +4128,6 @@ void I3C_Slave_ISR(uint8_t I3C_IF) 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 { - } - /* IBI and Hot-Join only */ /* Master Request handled in NOWMASTER */ if (I3C_GET_REG_STATUS(I3C_IF) & I3C_STATUS_EVENT_MASK) { @@ -4099,6 +4157,25 @@ void I3C_Slave_ISR(uint8_t I3C_IF) } } + if (bMATCHSS) { + 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 { + } + } + /* Force End RX DMA */ /* clear auto CCC */ @@ -4596,6 +4673,12 @@ static int i3c_npcm4xx_init(const struct device *dev) api_I3C_connect_bus(port, config->busno); hal_I3C_Config_Device(pDevice); + + /* set hj req as false */ + config->hj_req = I3C_HOT_JOIN_STATE_None; + + config->rst_reason = npcm4xx_get_reset_reason(); + return 0; } diff --git a/drivers/i3c/npcm4xx/i3c_drv.h b/drivers/i3c/npcm4xx/i3c_drv.h index 9d2464b7352d5a..09b1eda7db3e80 100644 --- a/drivers/i3c/npcm4xx/i3c_drv.h +++ b/drivers/i3c/npcm4xx/i3c_drv.h @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -98,6 +99,8 @@ struct i3c_npcm4xx_config { uint32_t irq; bool slave; bool secondary; + uint8_t hj_req; + enum npcm4xx_reset_reason rst_reason; uint32_t i3c_scl_hz; uint32_t i2c_scl_hz; /* uint16_t manufacture-id; PID[5:4] */ @@ -389,6 +392,12 @@ enum I3C_MSTATUS_IBITYPE_Enum { I3C_MSTATUS_IBITYPE_HotJoin = 3, }; +enum I3C_HOT_JOIN_STATE_Enum { + I3C_HOT_JOIN_STATE_None = 0, + I3C_HOT_JOIN_STATE_Request = 1, + I3C_HOT_JOIN_STATE_Queue = 2, +}; + enum I3C_MSTATUS_STATE_Enum { I3C_MSTATUS_STATE_IDLE = 0U, I3C_MSTATUS_STATE_SLVREQ = 1U, diff --git a/soc/arm/npcm4xx/common/soc_common.h b/soc/arm/npcm4xx/common/soc_common.h index ff22b49aa7432e..b46ba315a16f5e 100644 --- a/soc/arm/npcm4xx/common/soc_common.h +++ b/soc/arm/npcm4xx/common/soc_common.h @@ -4,6 +4,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +#ifndef _NUVOTON_NPCM4XX_SOC_COMMON_H_ +#define _NUVOTON_NPCM4XX_SOC_COMMON_H_ + /* one bit per 4K, total 32 * 8 * 4K = 1024K MAX */ #define BITMAP_ARRAY_PER_SIZE 0x20 #define BITMAP_LIST_SIZE 0x8 @@ -39,3 +42,5 @@ void npcm4xx_sram_vector_table_copy(void); /* use for replace/restore VTOR */ uintptr_t npcm4xx_vector_table_save(void); void npcm4xx_vector_table_restore(uintptr_t vtor); + +#endif /* _NUVOTON_NPCM4XX_SOC_COMMON_H_ */ From 55d9446c8df0cb76950cd4420f80437c2d5583a4 Mon Sep 17 00:00:00 2001 From: James Chiang Date: Wed, 11 Sep 2024 18:35:57 -0700 Subject: [PATCH 4/5] drivers: i3c: npcm4xx: add error handling when master read timeout add error handling when master read timeout. Signed-off-by: James Chiang --- drivers/i3c/i3c_npcm4xx.c | 66 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/drivers/i3c/i3c_npcm4xx.c b/drivers/i3c/i3c_npcm4xx.c index 697a880f96cd2d..17e9635f57b961 100644 --- a/drivers/i3c/i3c_npcm4xx.c +++ b/drivers/i3c/i3c_npcm4xx.c @@ -1787,6 +1787,35 @@ static void i3c_npcm4xx_reset(I3C_PORT_Enum port) irq_enable(config->irq); } +I3C_ErrCode_Enum hal_I3C_Stop_SlaveEvent(I3C_TASK_INFO_t *pTaskInfo) +{ + I3C_PORT_Enum port; + I3C_DEVICE_INFO_t *pDevice; + 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; + + ctrl = I3C_GET_REG_CTRL(port); + + /* clean up ibi data, extdata and event mask */ + ctrl &= ~(I3C_CTRL_IBIDATA_MASK | I3C_CTRL_EXTDATA_MASK | I3C_CTRL_EVENT_MASK); + + I3C_SET_REG_CTRL(port, ctrl); + + return I3C_ERR_OK; +} + I3C_ErrCode_Enum hal_I3C_Start_IBI(I3C_TASK_INFO_t *pTaskInfo) { I3C_PORT_Enum port; @@ -1810,6 +1839,12 @@ I3C_ErrCode_Enum hal_I3C_Start_IBI(I3C_TASK_INFO_t *pTaskInfo) pTask = pTaskInfo->pTask; pFrame = &pTask->pFrameList[pTask->frame_idx]; + if (I3C_GET_REG_CTRL(port) & I3C_CTRL_EVENT_MASK) { + LOG_WRN("Generarte IBI but CTRL in Progress: 0x%x\n", + I3C_GET_REG_CTRL(port)); + hal_I3C_Stop_SlaveEvent(pTaskInfo); + } + ctrl = I3C_GET_REG_CTRL(port); ctrl &= ~(I3C_CTRL_IBIDATA_MASK | I3C_CTRL_EXTDATA_MASK | I3C_CTRL_EVENT_MASK); @@ -1835,6 +1870,7 @@ I3C_ErrCode_Enum hal_I3C_Start_IBI(I3C_TASK_INFO_t *pTaskInfo) } ctrl |= I3C_CTRL_EVENT(I3C_CTRL_EVENT_IBI); + I3C_SET_REG_CTRL(port, ctrl); return I3C_ERR_OK; @@ -1859,6 +1895,12 @@ I3C_ErrCode_Enum hal_I3C_Start_Master_Request(I3C_TASK_INFO_t *pTaskInfo) ((pDevice->mode != I3C_DEVICE_MODE_SECONDARY_MASTER))) return I3C_ERR_PARAMETER_INVALID; + if (I3C_GET_REG_CTRL(port) & I3C_CTRL_EVENT_MASK) { + LOG_WRN("Generarte Master REQ but CTRL in Progress: 0x%x\n", + I3C_GET_REG_CTRL(port)); + hal_I3C_Stop_SlaveEvent(pTaskInfo); + } + 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); @@ -1871,6 +1913,7 @@ I3C_ErrCode_Enum hal_I3C_Start_Master_Request(I3C_TASK_INFO_t *pTaskInfo) ctrl = I3C_GET_REG_CTRL(port); ctrl |= I3C_CTRL_EVENT(I3C_CTRL_EVENT_MstReq); + I3C_SET_REG_CTRL(port, ctrl); return I3C_ERR_OK; } @@ -1934,6 +1977,12 @@ I3C_ErrCode_Enum hal_I3C_Start_HotJoin(I3C_TASK_INFO_t *pTaskInfo) goto hj_exit; } + if (I3C_GET_REG_CTRL(port) & I3C_CTRL_EVENT_MASK) { + LOG_WRN("Generarte HJ but CTRL in Progress: 0x%x\n", + I3C_GET_REG_CTRL(port)); + hal_I3C_Stop_SlaveEvent(pTaskInfo); + } + 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); @@ -2086,7 +2135,7 @@ I3C_ErrCode_Enum hal_I3C_Stop_Slave_TX(I3C_DEVICE_INFO_t *pDevice) PDMA->TDSTS = MaskBit(PDMA_OFFSET + pDevice->port); PDMA->CHCTL &= ~MaskBit(PDMA_OFFSET + pDevice->port); - datactrl |= I3C_MDATACTRL_FLUSHFB_MASK; + datactrl |= I3C_DATACTRL_FLUSHTB_MASK; I3C_SET_REG_DATACTRL(pDevice->port, datactrl); return I3C_ERR_OK; } @@ -2650,6 +2699,8 @@ int i3c_npcm4xx_slave_put_read_data(const struct device *dev, struct i3c_slave_p { struct i3c_npcm4xx_config *config; struct i3c_npcm4xx_obj *obj; + I3C_TASK_INFO_t *pTaskInfo; + I3C_TRANSFER_TASK_t *pTask; I3C_PORT_Enum port; uint32_t event_en; int ret; @@ -2730,7 +2781,7 @@ int i3c_npcm4xx_slave_put_read_data(const struct device *dev, struct i3c_slave_p } /* let slave drive SLVSTART until bus idle */ - api_I3C_Slave_Create_Task(protocol, txlen, &txlen, &rxlen, TxBuf, NULL, + pTaskInfo = api_I3C_Slave_Create_Task(protocol, txlen, &txlen, &rxlen, TxBuf, NULL, timeout, NULL, port, NOT_HIF); k_work_submit_to_queue(&npcm4xx_i3c_work_q[port], &work_send_ibi[port]); @@ -2739,6 +2790,17 @@ int i3c_npcm4xx_slave_put_read_data(const struct device *dev, struct i3c_slave_p if (iRet != 0) { LOG_ERR("wait master read timeout %d", iRet); + pTask = pTaskInfo->pTask; + /* cancel slave event */ + hal_I3C_Stop_SlaveEvent(pTaskInfo); + /* remove ibi task from queue */ + api_I3C_Slave_End_Request((uint32_t)pTask); + /* stop TX and DMA */ + hal_I3C_Stop_Slave_TX(pDevice); + /* release memory resource */ + api_I3C_Slave_Finish_Response(pDevice); + k_mutex_unlock(&pDevice->lock); + return iRet; } } From 159bb0d3be8c0551e3a4f5e0354af73a4f82f0d7 Mon Sep 17 00:00:00 2001 From: James Chiang Date: Wed, 18 Sep 2024 18:29:47 -0700 Subject: [PATCH 5/5] drivers: gpio: npcm4xx: fix wrong setting when setup gpio open drain mode fix wrong setting when setup gpio open drain mode. only output open drain mode with pull-up setting need enable DEVALTCX bit. Signed-off-by: James Chiang --- drivers/gpio/gpio_npcm4xx.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/gpio/gpio_npcm4xx.c b/drivers/gpio/gpio_npcm4xx.c index 70970dcfef82a6..0d9e4a635811d5 100644 --- a/drivers/gpio/gpio_npcm4xx.c +++ b/drivers/gpio/gpio_npcm4xx.c @@ -146,13 +146,14 @@ static int gpio_npcm4xx_config(const struct device *dev, else inst->PTYPE &= ~mask; - /* Select opend drain with pull up need enable GPIO_PULL_EN */ - if (((flags & GPIO_OPEN_DRAIN) != 0) && - ((flags & GPIO_PULL_UP) != 0)) { - inst_scfg->DEVALTCX |= BIT(NPCM4XX_DEVALTCX_GPIO_PULL_EN); + /* Open drain output mode want to enable internal pull up/down */ + if ((flags & GPIO_OPEN_DRAIN) && (flags & GPIO_OUTPUT)) { + if ((flags & GPIO_PULL_UP)) { + inst_scfg->DEVALTCX |= BIT(NPCM4XX_DEVALTCX_GPIO_PULL_EN); + } } - /* Select pull-up/down of GPIO 0:pull-up 1:pull-down */ + /* Enable and select pull-up/down of GPIO 0:pull-up 1:pull-down */ if ((flags & GPIO_PULL_UP) != 0) { inst->PPUD &= ~mask; inst->PPULL |= mask;