2828#define SWRM_COMP_PARAMS_DIN_PORTS_MASK GENMASK(9, 5)
2929#define SWRM_INTERRUPT_STATUS 0x200
3030#define SWRM_INTERRUPT_STATUS_RMSK GENMASK(16, 0)
31+ #define SWRM_INTERRUPT_STATUS_SLAVE_PEND_IRQ BIT(0)
3132#define SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED BIT(1)
3233#define SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS BIT(2)
34+ #define SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET BIT(3)
35+ #define SWRM_INTERRUPT_STATUS_RD_FIFO_OVERFLOW BIT(4)
36+ #define SWRM_INTERRUPT_STATUS_RD_FIFO_UNDERFLOW BIT(5)
37+ #define SWRM_INTERRUPT_STATUS_WR_CMD_FIFO_OVERFLOW BIT(6)
3338#define SWRM_INTERRUPT_STATUS_CMD_ERROR BIT(7)
39+ #define SWRM_INTERRUPT_STATUS_DOUT_PORT_COLLISION BIT(8)
40+ #define SWRM_INTERRUPT_STATUS_READ_EN_RD_VALID_MISMATCH BIT(9)
3441#define SWRM_INTERRUPT_STATUS_SPECIAL_CMD_ID_FINISHED BIT(10)
42+ #define SWRM_INTERRUPT_STATUS_BUS_RESET_FINISHED_V2 BIT(13)
43+ #define SWRM_INTERRUPT_STATUS_CLK_STOP_FINISHED_V2 BIT(14)
44+ #define SWRM_INTERRUPT_STATUS_EXT_CLK_STOP_WAKEUP BIT(16)
45+ #define SWRM_INTERRUPT_MAX 17
3546#define SWRM_INTERRUPT_MASK_ADDR 0x204
3647#define SWRM_INTERRUPT_CLEAR 0x208
3748#define SWRM_INTERRUPT_CPU_EN 0x210
5869#define SWRM_MCP_STATUS_BANK_NUM_MASK BIT(0)
5970#define SWRM_MCP_SLV_STATUS 0x1090
6071#define SWRM_MCP_SLV_STATUS_MASK GENMASK(1, 0)
72+ #define SWRM_MCP_SLV_STATUS_SZ 2
6173#define SWRM_DP_PORT_CTRL_BANK (n , m ) (0x1124 + 0x100 * (n - 1) + 0x40 * m)
6274#define SWRM_DP_PORT_CTRL_2_BANK (n , m ) (0x1128 + 0x100 * (n - 1) + 0x40 * m)
6375#define SWRM_DP_BLOCK_CTRL_1 (n ) (0x112C + 0x100 * (n - 1))
@@ -123,6 +135,7 @@ struct qcom_swrm_ctrl {
123135 int rows_index ;
124136 unsigned long dout_port_mask ;
125137 unsigned long din_port_mask ;
138+ u32 intr_mask ;
126139 u8 rcmd_id ;
127140 u8 wcmd_id ;
128141 struct qcom_swrm_port_config pconfig [QCOM_SDW_MAX_PORTS ];
@@ -305,6 +318,25 @@ static int qcom_swrm_cmd_fifo_rd_cmd(struct qcom_swrm_ctrl *swrm,
305318 return SDW_CMD_IGNORED ;
306319}
307320
321+ static int qcom_swrm_get_alert_slave_dev_num (struct qcom_swrm_ctrl * ctrl )
322+ {
323+ u32 val , status ;
324+ int dev_num ;
325+
326+ ctrl -> reg_read (ctrl , SWRM_MCP_SLV_STATUS , & val );
327+
328+ for (dev_num = 0 ; dev_num < SDW_MAX_DEVICES ; dev_num ++ ) {
329+ status = (val >> (dev_num * SWRM_MCP_SLV_STATUS_SZ ));
330+
331+ if ((status & SWRM_MCP_SLV_STATUS_MASK ) == SDW_SLAVE_ALERT ) {
332+ ctrl -> status [dev_num ] = status ;
333+ return dev_num ;
334+ }
335+ }
336+
337+ return - EINVAL ;
338+ }
339+
308340static void qcom_swrm_get_device_status (struct qcom_swrm_ctrl * ctrl )
309341{
310342 u32 val ;
@@ -323,36 +355,112 @@ static void qcom_swrm_get_device_status(struct qcom_swrm_ctrl *ctrl)
323355
324356static irqreturn_t qcom_swrm_irq_handler (int irq , void * dev_id )
325357{
326- struct qcom_swrm_ctrl * ctrl = dev_id ;
327- u32 sts , value ;
358+ struct qcom_swrm_ctrl * swrm = dev_id ;
359+ u32 value , intr_sts , intr_sts_masked ;
360+ u32 i ;
361+ u8 devnum = 0 ;
362+ int ret = IRQ_HANDLED ;
328363
329- ctrl -> reg_read (ctrl , SWRM_INTERRUPT_STATUS , & sts );
364+ swrm -> reg_read (swrm , SWRM_INTERRUPT_STATUS , & intr_sts );
365+ intr_sts_masked = intr_sts & swrm -> intr_mask ;
330366
331- if (sts & SWRM_INTERRUPT_STATUS_CMD_ERROR ) {
332- ctrl -> reg_read (ctrl , SWRM_CMD_FIFO_STATUS , & value );
333- dev_err_ratelimited (ctrl -> dev ,
334- "CMD error, fifo status 0x%x\n" ,
335- value );
336- ctrl -> reg_write (ctrl , SWRM_CMD_FIFO_CMD , 0x1 );
337- }
338-
339- if ((sts & SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED ) ||
340- sts & SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS ) {
341- qcom_swrm_get_device_status (ctrl );
342- sdw_handle_slave_status (& ctrl -> bus , ctrl -> status );
343- }
344-
345- /**
346- * clear the interrupt before complete() is called, as complete can
347- * schedule new read/writes which require interrupts, clearing the
348- * interrupt would avoid missing interrupts in such cases.
349- */
350- ctrl -> reg_write (ctrl , SWRM_INTERRUPT_CLEAR , sts );
367+ do {
368+ for (i = 0 ; i < SWRM_INTERRUPT_MAX ; i ++ ) {
369+ value = intr_sts_masked & BIT (i );
370+ if (!value )
371+ continue ;
372+
373+ switch (value ) {
374+ case SWRM_INTERRUPT_STATUS_SLAVE_PEND_IRQ :
375+ devnum = qcom_swrm_get_alert_slave_dev_num (swrm );
376+ if (devnum < 0 ) {
377+ dev_err_ratelimited (swrm -> dev ,
378+ "no slave alert found.spurious interrupt\n" );
379+ } else {
380+ sdw_handle_slave_status (& swrm -> bus , swrm -> status );
381+ }
351382
352- if (sts & SWRM_INTERRUPT_STATUS_SPECIAL_CMD_ID_FINISHED )
353- complete (& ctrl -> broadcast );
383+ break ;
384+ case SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED :
385+ case SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS :
386+ dev_err_ratelimited (swrm -> dev , "%s: SWR new slave attached\n" ,
387+ __func__ );
388+ qcom_swrm_get_device_status (swrm );
389+ sdw_handle_slave_status (& swrm -> bus , swrm -> status );
390+ break ;
391+ case SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET :
392+ dev_err_ratelimited (swrm -> dev ,
393+ "%s: SWR bus clsh detected\n" ,
394+ __func__ );
395+ swrm -> intr_mask &= ~SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET ;
396+ swrm -> reg_write (swrm , SWRM_INTERRUPT_CPU_EN , swrm -> intr_mask );
397+ break ;
398+ case SWRM_INTERRUPT_STATUS_RD_FIFO_OVERFLOW :
399+ swrm -> reg_read (swrm , SWRM_CMD_FIFO_STATUS , & value );
400+ dev_err_ratelimited (swrm -> dev ,
401+ "%s: SWR read FIFO overflow fifo status 0x%x\n" ,
402+ __func__ , value );
403+ break ;
404+ case SWRM_INTERRUPT_STATUS_RD_FIFO_UNDERFLOW :
405+ swrm -> reg_read (swrm , SWRM_CMD_FIFO_STATUS , & value );
406+ dev_err_ratelimited (swrm -> dev ,
407+ "%s: SWR read FIFO underflow fifo status 0x%x\n" ,
408+ __func__ , value );
409+ break ;
410+ case SWRM_INTERRUPT_STATUS_WR_CMD_FIFO_OVERFLOW :
411+ swrm -> reg_read (swrm , SWRM_CMD_FIFO_STATUS , & value );
412+ dev_err (swrm -> dev ,
413+ "%s: SWR write FIFO overflow fifo status %x\n" ,
414+ __func__ , value );
415+ swrm -> reg_write (swrm , SWRM_CMD_FIFO_CMD , 0x1 );
416+ break ;
417+ case SWRM_INTERRUPT_STATUS_CMD_ERROR :
418+ swrm -> reg_read (swrm , SWRM_CMD_FIFO_STATUS , & value );
419+ dev_err_ratelimited (swrm -> dev ,
420+ "%s: SWR CMD error, fifo status 0x%x, flushing fifo\n" ,
421+ __func__ , value );
422+ swrm -> reg_write (swrm , SWRM_CMD_FIFO_CMD , 0x1 );
423+ break ;
424+ case SWRM_INTERRUPT_STATUS_DOUT_PORT_COLLISION :
425+ dev_err_ratelimited (swrm -> dev ,
426+ "%s: SWR Port collision detected\n" ,
427+ __func__ );
428+ swrm -> intr_mask &= ~SWRM_INTERRUPT_STATUS_DOUT_PORT_COLLISION ;
429+ swrm -> reg_write (swrm ,
430+ SWRM_INTERRUPT_CPU_EN , swrm -> intr_mask );
431+ break ;
432+ case SWRM_INTERRUPT_STATUS_READ_EN_RD_VALID_MISMATCH :
433+ dev_err_ratelimited (swrm -> dev ,
434+ "%s: SWR read enable valid mismatch\n" ,
435+ __func__ );
436+ swrm -> intr_mask &=
437+ ~SWRM_INTERRUPT_STATUS_READ_EN_RD_VALID_MISMATCH ;
438+ swrm -> reg_write (swrm ,
439+ SWRM_INTERRUPT_CPU_EN , swrm -> intr_mask );
440+ break ;
441+ case SWRM_INTERRUPT_STATUS_SPECIAL_CMD_ID_FINISHED :
442+ complete (& swrm -> broadcast );
443+ break ;
444+ case SWRM_INTERRUPT_STATUS_BUS_RESET_FINISHED_V2 :
445+ break ;
446+ case SWRM_INTERRUPT_STATUS_CLK_STOP_FINISHED_V2 :
447+ break ;
448+ case SWRM_INTERRUPT_STATUS_EXT_CLK_STOP_WAKEUP :
449+ break ;
450+ default :
451+ dev_err_ratelimited (swrm -> dev ,
452+ "%s: SWR unknown interrupt value: %d\n" ,
453+ __func__ , value );
454+ ret = IRQ_NONE ;
455+ break ;
456+ }
457+ }
458+ swrm -> reg_write (swrm , SWRM_INTERRUPT_CLEAR , intr_sts );
459+ swrm -> reg_read (swrm , SWRM_INTERRUPT_STATUS , & intr_sts );
460+ intr_sts_masked = intr_sts & swrm -> intr_mask ;
461+ } while (intr_sts_masked );
354462
355- return IRQ_HANDLED ;
463+ return ret ;
356464}
357465
358466static int qcom_swrm_init (struct qcom_swrm_ctrl * ctrl )
@@ -368,6 +476,7 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl)
368476 /* Disable Auto enumeration */
369477 ctrl -> reg_write (ctrl , SWRM_ENUMERATOR_CFG_ADDR , 0 );
370478
479+ ctrl -> intr_mask = SWRM_INTERRUPT_STATUS_RMSK ;
371480 /* Mask soundwire interrupts */
372481 ctrl -> reg_write (ctrl , SWRM_INTERRUPT_MASK_ADDR ,
373482 SWRM_INTERRUPT_STATUS_RMSK );
0 commit comments