soc: mediatek: mtk-cmdq: Add cmdq_pkt_poll_addr() function
[linux-2.6-block.git] / drivers / soc / mediatek / mtk-cmdq-helper.c
index 4cd1a25866a9a8b3998aaa2600df79b977ef15b0..ee55992f6491177de04400beca0b7157caeb255b 100644 (file)
@@ -12,6 +12,8 @@
 
 #define CMDQ_WRITE_ENABLE_MASK BIT(0)
 #define CMDQ_POLL_ENABLE_MASK  BIT(0)
+/* dedicate the last GPR_R15 to assign the register address to be poll */
+#define CMDQ_POLL_ADDR_GPR     (15)
 #define CMDQ_EOC_IRQ_EN                BIT(0)
 #define CMDQ_REG_TYPE          1
 #define CMDQ_JUMP_RELATIVE     0
@@ -397,6 +399,53 @@ int cmdq_pkt_poll_mask(struct cmdq_pkt *pkt, u8 subsys,
 }
 EXPORT_SYMBOL(cmdq_pkt_poll_mask);
 
+int cmdq_pkt_poll_addr(struct cmdq_pkt *pkt, dma_addr_t addr, u32 value, u32 mask)
+{
+       struct cmdq_instruction inst = { {0} };
+       u8 use_mask = 0;
+       int ret;
+
+       /*
+        * Append an MASK instruction to set the mask for following POLL instruction
+        * which enables use_mask bit.
+        */
+       if (mask != GENMASK(31, 0)) {
+               inst.op = CMDQ_CODE_MASK;
+               inst.mask = ~mask;
+               ret = cmdq_pkt_append_command(pkt, inst);
+               if (ret < 0)
+                       return ret;
+               use_mask = CMDQ_POLL_ENABLE_MASK;
+       }
+
+       /*
+        * POLL is an legacy operation in GCE and it does not support SPR and CMDQ_CODE_LOGIC,
+        * so it can not use cmdq_pkt_assign to keep polling register address to SPR.
+        * If user wants to poll a register address which doesn't have a subsys id,
+        * user needs to use GPR and CMDQ_CODE_MASK to move polling register address to GPR.
+        */
+       inst.op = CMDQ_CODE_MASK;
+       inst.dst_t = CMDQ_REG_TYPE;
+       inst.sop = CMDQ_POLL_ADDR_GPR;
+       inst.value = addr;
+       ret = cmdq_pkt_append_command(pkt, inst);
+       if (ret < 0)
+               return ret;
+
+       /* Append POLL instruction to poll the register address assign to GPR previously. */
+       inst.op = CMDQ_CODE_POLL;
+       inst.dst_t = CMDQ_REG_TYPE;
+       inst.sop = CMDQ_POLL_ADDR_GPR;
+       inst.offset = use_mask;
+       inst.value = value;
+       ret = cmdq_pkt_append_command(pkt, inst);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+EXPORT_SYMBOL(cmdq_pkt_poll_addr);
+
 int cmdq_pkt_assign(struct cmdq_pkt *pkt, u16 reg_idx, u32 value)
 {
        struct cmdq_instruction inst = {};