@@ -896,27 +896,35 @@ static int svc_i3c_master_do_daa(struct i3c_master_controller *m)
896896static int svc_i3c_master_read (struct svc_i3c_master * master ,
897897 u8 * in , unsigned int len )
898898{
899- int offset = 0 , i , ret ;
900- u32 mdctrl ;
899+ int offset = 0 , i ;
900+ u32 mdctrl , mstatus ;
901+ bool completed = false;
902+ unsigned int count ;
903+ unsigned long start = jiffies ;
901904
902- while (offset < len ) {
903- unsigned int count ;
905+ while (!completed ) {
906+ mstatus = readl (master -> regs + SVC_I3C_MSTATUS );
907+ if (SVC_I3C_MSTATUS_COMPLETE (mstatus ) != 0 )
908+ completed = true;
904909
905- ret = readl_poll_timeout (master -> regs + SVC_I3C_MDATACTRL ,
906- mdctrl ,
907- !(mdctrl & SVC_I3C_MDATACTRL_RXEMPTY ),
908- 0 , 1000 );
909- if (ret )
910- return ret ;
910+ if (time_after (jiffies , start + msecs_to_jiffies (1000 ))) {
911+ dev_dbg (master -> dev , "I3C read timeout\n" );
912+ return - ETIMEDOUT ;
913+ }
911914
915+ mdctrl = readl (master -> regs + SVC_I3C_MDATACTRL );
912916 count = SVC_I3C_MDATACTRL_RXCOUNT (mdctrl );
917+ if (offset + count > len ) {
918+ dev_err (master -> dev , "I3C receive length too long!\n" );
919+ return - EINVAL ;
920+ }
913921 for (i = 0 ; i < count ; i ++ )
914922 in [offset + i ] = readl (master -> regs + SVC_I3C_MRDATAB );
915923
916924 offset += count ;
917925 }
918926
919- return 0 ;
927+ return offset ;
920928}
921929
922930static int svc_i3c_master_write (struct svc_i3c_master * master ,
@@ -949,7 +957,7 @@ static int svc_i3c_master_write(struct svc_i3c_master *master,
949957static int svc_i3c_master_xfer (struct svc_i3c_master * master ,
950958 bool rnw , unsigned int xfer_type , u8 addr ,
951959 u8 * in , const u8 * out , unsigned int xfer_len ,
952- unsigned int read_len , bool continued )
960+ unsigned int * read_len , bool continued )
953961{
954962 u32 reg ;
955963 int ret ;
@@ -959,7 +967,7 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,
959967 SVC_I3C_MCTRL_IBIRESP_NACK |
960968 SVC_I3C_MCTRL_DIR (rnw ) |
961969 SVC_I3C_MCTRL_ADDR (addr ) |
962- SVC_I3C_MCTRL_RDTERM (read_len ),
970+ SVC_I3C_MCTRL_RDTERM (* read_len ),
963971 master -> regs + SVC_I3C_MCTRL );
964972
965973 ret = readl_poll_timeout (master -> regs + SVC_I3C_MSTATUS , reg ,
@@ -971,17 +979,27 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,
971979 ret = svc_i3c_master_read (master , in , xfer_len );
972980 else
973981 ret = svc_i3c_master_write (master , out , xfer_len );
974- if (ret )
982+ if (ret < 0 )
975983 goto emit_stop ;
976984
985+ if (rnw )
986+ * read_len = ret ;
987+
977988 ret = readl_poll_timeout (master -> regs + SVC_I3C_MSTATUS , reg ,
978989 SVC_I3C_MSTATUS_COMPLETE (reg ), 0 , 1000 );
979990 if (ret )
980991 goto emit_stop ;
981992
982- if (!continued )
993+ writel (SVC_I3C_MINT_COMPLETE , master -> regs + SVC_I3C_MSTATUS );
994+
995+ if (!continued ) {
983996 svc_i3c_master_emit_stop (master );
984997
998+ /* Wait idle if stop is sent. */
999+ readl_poll_timeout (master -> regs + SVC_I3C_MSTATUS , reg ,
1000+ SVC_I3C_MSTATUS_STATE_IDLE (reg ), 0 , 1000 );
1001+ }
1002+
9851003 return 0 ;
9861004
9871005emit_stop :
@@ -1039,12 +1057,15 @@ static void svc_i3c_master_start_xfer_locked(struct svc_i3c_master *master)
10391057 if (!xfer )
10401058 return ;
10411059
1060+ svc_i3c_master_clear_merrwarn (master );
1061+ svc_i3c_master_flush_fifo (master );
1062+
10421063 for (i = 0 ; i < xfer -> ncmds ; i ++ ) {
10431064 struct svc_i3c_cmd * cmd = & xfer -> cmds [i ];
10441065
10451066 ret = svc_i3c_master_xfer (master , cmd -> rnw , xfer -> type ,
10461067 cmd -> addr , cmd -> in , cmd -> out ,
1047- cmd -> len , cmd -> read_len ,
1068+ cmd -> len , & cmd -> read_len ,
10481069 cmd -> continued );
10491070 if (ret )
10501071 break ;
@@ -1173,6 +1194,9 @@ static int svc_i3c_master_send_direct_ccc_cmd(struct svc_i3c_master *master,
11731194 if (!wait_for_completion_timeout (& xfer -> comp , msecs_to_jiffies (1000 )))
11741195 svc_i3c_master_dequeue_xfer (master , xfer );
11751196
1197+ if (cmd -> read_len != xfer_len )
1198+ ccc -> dests [0 ].payload .len = cmd -> read_len ;
1199+
11761200 ret = xfer -> ret ;
11771201 svc_i3c_master_free_xfer (xfer );
11781202
0 commit comments