Loading drivers/soc/mediatek/mtk-cmdq-helper.c +121 −26 Original line number Diff line number Diff line Loading @@ -9,10 +9,52 @@ #include <linux/mailbox_controller.h> #include <linux/soc/mediatek/mtk-cmdq.h> #define CMDQ_ARG_A_WRITE_MASK 0xffff #define CMDQ_WRITE_ENABLE_MASK BIT(0) #define CMDQ_POLL_ENABLE_MASK BIT(0) #define CMDQ_EOC_IRQ_EN BIT(0) struct cmdq_instruction { union { u32 value; u32 mask; }; union { u16 offset; u16 event; }; u8 subsys; u8 op; }; int cmdq_dev_get_client_reg(struct device *dev, struct cmdq_client_reg *client_reg, int idx) { struct of_phandle_args spec; int err; if (!client_reg) return -ENOENT; err = of_parse_phandle_with_fixed_args(dev->of_node, "mediatek,gce-client-reg", 3, idx, &spec); if (err < 0) { dev_err(dev, "error %d can't parse gce-client-reg property (%d)", err, idx); return err; } client_reg->subsys = (u8)spec.args[0]; client_reg->offset = (u16)spec.args[1]; client_reg->size = (u16)spec.args[2]; of_node_put(spec.np); return 0; } EXPORT_SYMBOL(cmdq_dev_get_client_reg); static void cmdq_client_timeout(struct timer_list *t) { struct cmdq_client *client = from_timer(client, t, timer); Loading Loading @@ -108,10 +150,10 @@ void cmdq_pkt_destroy(struct cmdq_pkt *pkt) } EXPORT_SYMBOL(cmdq_pkt_destroy); static int cmdq_pkt_append_command(struct cmdq_pkt *pkt, enum cmdq_code code, u32 arg_a, u32 arg_b) static int cmdq_pkt_append_command(struct cmdq_pkt *pkt, struct cmdq_instruction inst) { u64 *cmd_ptr; struct cmdq_instruction *cmd_ptr; if (unlikely(pkt->cmd_buf_size + CMDQ_INST_SIZE > pkt->buf_size)) { /* Loading @@ -127,8 +169,9 @@ static int cmdq_pkt_append_command(struct cmdq_pkt *pkt, enum cmdq_code code, __func__, (u32)pkt->buf_size); return -ENOMEM; } cmd_ptr = pkt->va_base + pkt->cmd_buf_size; (*cmd_ptr) = (u64)((code << CMDQ_OP_CODE_SHIFT) | arg_a) << 32 | arg_b; *cmd_ptr = inst; pkt->cmd_buf_size += CMDQ_INST_SIZE; return 0; Loading @@ -136,24 +179,34 @@ static int cmdq_pkt_append_command(struct cmdq_pkt *pkt, enum cmdq_code code, int cmdq_pkt_write(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value) { u32 arg_a = (offset & CMDQ_ARG_A_WRITE_MASK) | (subsys << CMDQ_SUBSYS_SHIFT); struct cmdq_instruction inst; inst.op = CMDQ_CODE_WRITE; inst.value = value; inst.offset = offset; inst.subsys = subsys; return cmdq_pkt_append_command(pkt, CMDQ_CODE_WRITE, arg_a, value); return cmdq_pkt_append_command(pkt, inst); } EXPORT_SYMBOL(cmdq_pkt_write); int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value, u32 mask) { u32 offset_mask = offset; int err = 0; struct cmdq_instruction inst = { {0} }; u16 offset_mask = offset; int err; if (mask != 0xffffffff) { err = cmdq_pkt_append_command(pkt, CMDQ_CODE_MASK, 0, ~mask); inst.op = CMDQ_CODE_MASK; inst.mask = ~mask; err = cmdq_pkt_append_command(pkt, inst); if (err < 0) return err; offset_mask |= CMDQ_WRITE_ENABLE_MASK; } err |= cmdq_pkt_write(pkt, subsys, offset_mask, value); err = cmdq_pkt_write(pkt, subsys, offset_mask, value); return err; } Loading @@ -161,43 +214,85 @@ EXPORT_SYMBOL(cmdq_pkt_write_mask); int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u16 event) { u32 arg_b; struct cmdq_instruction inst = { {0} }; if (event >= CMDQ_MAX_EVENT) return -EINVAL; /* * WFE arg_b * bit 0-11: wait value * bit 15: 1 - wait, 0 - no wait * bit 16-27: update value * bit 31: 1 - update, 0 - no update */ arg_b = CMDQ_WFE_UPDATE | CMDQ_WFE_WAIT | CMDQ_WFE_WAIT_VALUE; inst.op = CMDQ_CODE_WFE; inst.value = CMDQ_WFE_OPTION; inst.event = event; return cmdq_pkt_append_command(pkt, CMDQ_CODE_WFE, event, arg_b); return cmdq_pkt_append_command(pkt, inst); } EXPORT_SYMBOL(cmdq_pkt_wfe); int cmdq_pkt_clear_event(struct cmdq_pkt *pkt, u16 event) { struct cmdq_instruction inst = { {0} }; if (event >= CMDQ_MAX_EVENT) return -EINVAL; return cmdq_pkt_append_command(pkt, CMDQ_CODE_WFE, event, CMDQ_WFE_UPDATE); inst.op = CMDQ_CODE_WFE; inst.value = CMDQ_WFE_UPDATE; inst.event = event; return cmdq_pkt_append_command(pkt, inst); } EXPORT_SYMBOL(cmdq_pkt_clear_event); int cmdq_pkt_poll(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value) { struct cmdq_instruction inst = { {0} }; int err; inst.op = CMDQ_CODE_POLL; inst.value = value; inst.offset = offset; inst.subsys = subsys; err = cmdq_pkt_append_command(pkt, inst); return err; } EXPORT_SYMBOL(cmdq_pkt_poll); int cmdq_pkt_poll_mask(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value, u32 mask) { struct cmdq_instruction inst = { {0} }; int err; inst.op = CMDQ_CODE_MASK; inst.mask = ~mask; err = cmdq_pkt_append_command(pkt, inst); if (err < 0) return err; offset = offset | CMDQ_POLL_ENABLE_MASK; err = cmdq_pkt_poll(pkt, subsys, offset, value); return err; } EXPORT_SYMBOL(cmdq_pkt_poll_mask); static int cmdq_pkt_finalize(struct cmdq_pkt *pkt) { struct cmdq_instruction inst = { {0} }; int err; /* insert EOC and generate IRQ for each command iteration */ err = cmdq_pkt_append_command(pkt, CMDQ_CODE_EOC, 0, CMDQ_EOC_IRQ_EN); inst.op = CMDQ_CODE_EOC; inst.value = CMDQ_EOC_IRQ_EN; err = cmdq_pkt_append_command(pkt, inst); if (err < 0) return err; /* JUMP to end */ err |= cmdq_pkt_append_command(pkt, CMDQ_CODE_JUMP, 0, CMDQ_JUMP_PASS); inst.op = CMDQ_CODE_JUMP; inst.value = CMDQ_JUMP_PASS; err = cmdq_pkt_append_command(pkt, inst); return err; } Loading include/linux/mailbox/mtk-cmdq-mailbox.h +11 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,16 @@ #define CMDQ_WFE_WAIT BIT(15) #define CMDQ_WFE_WAIT_VALUE 0x1 /* * WFE arg_b * bit 0-11: wait value * bit 15: 1 - wait, 0 - no wait * bit 16-27: update value * bit 31: 1 - update, 0 - no update */ #define CMDQ_WFE_OPTION (CMDQ_WFE_UPDATE | CMDQ_WFE_WAIT | \ CMDQ_WFE_WAIT_VALUE) /** cmdq event maximum */ #define CMDQ_MAX_EVENT 0x3ff Loading @@ -45,6 +55,7 @@ enum cmdq_code { CMDQ_CODE_MASK = 0x02, CMDQ_CODE_WRITE = 0x04, CMDQ_CODE_POLL = 0x08, CMDQ_CODE_JUMP = 0x10, CMDQ_CODE_WFE = 0x20, CMDQ_CODE_EOC = 0x40, Loading include/linux/soc/mediatek/mtk-cmdq.h +53 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,12 @@ struct cmdq_pkt; struct cmdq_client_reg { u8 subsys; u16 offset; u16 size; }; struct cmdq_client { spinlock_t lock; u32 pkt_cnt; Loading @@ -24,6 +30,21 @@ struct cmdq_client { u32 timeout_ms; /* in unit of microsecond */ }; /** * cmdq_dev_get_client_reg() - parse cmdq client reg from the device * node of CMDQ client * @dev: device of CMDQ mailbox client * @client_reg: CMDQ client reg pointer * @idx: the index of desired reg * * Return: 0 for success; else the error code is returned * * Help CMDQ client parsing the cmdq client reg * from the device node of CMDQ client. */ int cmdq_dev_get_client_reg(struct device *dev, struct cmdq_client_reg *client_reg, int idx); /** * cmdq_mbox_create() - create CMDQ mailbox client and channel * @dev: device of CMDQ mailbox client Loading Loading @@ -99,6 +120,38 @@ int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u16 event); */ int cmdq_pkt_clear_event(struct cmdq_pkt *pkt, u16 event); /** * cmdq_pkt_poll() - Append polling command to the CMDQ packet, ask GCE to * execute an instruction that wait for a specified * hardware register to check for the value w/o mask. * All GCE hardware threads will be blocked by this * instruction. * @pkt: the CMDQ packet * @subsys: the CMDQ sub system code * @offset: register offset from CMDQ sub system * @value: the specified target register value * * Return: 0 for success; else the error code is returned */ int cmdq_pkt_poll(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value); /** * cmdq_pkt_poll_mask() - Append polling command to the CMDQ packet, ask GCE to * execute an instruction that wait for a specified * hardware register to check for the value w/ mask. * All GCE hardware threads will be blocked by this * instruction. * @pkt: the CMDQ packet * @subsys: the CMDQ sub system code * @offset: register offset from CMDQ sub system * @value: the specified target register value * @mask: the specified target register mask * * Return: 0 for success; else the error code is returned */ int cmdq_pkt_poll_mask(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value, u32 mask); /** * cmdq_pkt_flush_async() - trigger CMDQ to asynchronously execute the CMDQ * packet and call back at the end of done packet Loading Loading
drivers/soc/mediatek/mtk-cmdq-helper.c +121 −26 Original line number Diff line number Diff line Loading @@ -9,10 +9,52 @@ #include <linux/mailbox_controller.h> #include <linux/soc/mediatek/mtk-cmdq.h> #define CMDQ_ARG_A_WRITE_MASK 0xffff #define CMDQ_WRITE_ENABLE_MASK BIT(0) #define CMDQ_POLL_ENABLE_MASK BIT(0) #define CMDQ_EOC_IRQ_EN BIT(0) struct cmdq_instruction { union { u32 value; u32 mask; }; union { u16 offset; u16 event; }; u8 subsys; u8 op; }; int cmdq_dev_get_client_reg(struct device *dev, struct cmdq_client_reg *client_reg, int idx) { struct of_phandle_args spec; int err; if (!client_reg) return -ENOENT; err = of_parse_phandle_with_fixed_args(dev->of_node, "mediatek,gce-client-reg", 3, idx, &spec); if (err < 0) { dev_err(dev, "error %d can't parse gce-client-reg property (%d)", err, idx); return err; } client_reg->subsys = (u8)spec.args[0]; client_reg->offset = (u16)spec.args[1]; client_reg->size = (u16)spec.args[2]; of_node_put(spec.np); return 0; } EXPORT_SYMBOL(cmdq_dev_get_client_reg); static void cmdq_client_timeout(struct timer_list *t) { struct cmdq_client *client = from_timer(client, t, timer); Loading Loading @@ -108,10 +150,10 @@ void cmdq_pkt_destroy(struct cmdq_pkt *pkt) } EXPORT_SYMBOL(cmdq_pkt_destroy); static int cmdq_pkt_append_command(struct cmdq_pkt *pkt, enum cmdq_code code, u32 arg_a, u32 arg_b) static int cmdq_pkt_append_command(struct cmdq_pkt *pkt, struct cmdq_instruction inst) { u64 *cmd_ptr; struct cmdq_instruction *cmd_ptr; if (unlikely(pkt->cmd_buf_size + CMDQ_INST_SIZE > pkt->buf_size)) { /* Loading @@ -127,8 +169,9 @@ static int cmdq_pkt_append_command(struct cmdq_pkt *pkt, enum cmdq_code code, __func__, (u32)pkt->buf_size); return -ENOMEM; } cmd_ptr = pkt->va_base + pkt->cmd_buf_size; (*cmd_ptr) = (u64)((code << CMDQ_OP_CODE_SHIFT) | arg_a) << 32 | arg_b; *cmd_ptr = inst; pkt->cmd_buf_size += CMDQ_INST_SIZE; return 0; Loading @@ -136,24 +179,34 @@ static int cmdq_pkt_append_command(struct cmdq_pkt *pkt, enum cmdq_code code, int cmdq_pkt_write(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value) { u32 arg_a = (offset & CMDQ_ARG_A_WRITE_MASK) | (subsys << CMDQ_SUBSYS_SHIFT); struct cmdq_instruction inst; inst.op = CMDQ_CODE_WRITE; inst.value = value; inst.offset = offset; inst.subsys = subsys; return cmdq_pkt_append_command(pkt, CMDQ_CODE_WRITE, arg_a, value); return cmdq_pkt_append_command(pkt, inst); } EXPORT_SYMBOL(cmdq_pkt_write); int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value, u32 mask) { u32 offset_mask = offset; int err = 0; struct cmdq_instruction inst = { {0} }; u16 offset_mask = offset; int err; if (mask != 0xffffffff) { err = cmdq_pkt_append_command(pkt, CMDQ_CODE_MASK, 0, ~mask); inst.op = CMDQ_CODE_MASK; inst.mask = ~mask; err = cmdq_pkt_append_command(pkt, inst); if (err < 0) return err; offset_mask |= CMDQ_WRITE_ENABLE_MASK; } err |= cmdq_pkt_write(pkt, subsys, offset_mask, value); err = cmdq_pkt_write(pkt, subsys, offset_mask, value); return err; } Loading @@ -161,43 +214,85 @@ EXPORT_SYMBOL(cmdq_pkt_write_mask); int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u16 event) { u32 arg_b; struct cmdq_instruction inst = { {0} }; if (event >= CMDQ_MAX_EVENT) return -EINVAL; /* * WFE arg_b * bit 0-11: wait value * bit 15: 1 - wait, 0 - no wait * bit 16-27: update value * bit 31: 1 - update, 0 - no update */ arg_b = CMDQ_WFE_UPDATE | CMDQ_WFE_WAIT | CMDQ_WFE_WAIT_VALUE; inst.op = CMDQ_CODE_WFE; inst.value = CMDQ_WFE_OPTION; inst.event = event; return cmdq_pkt_append_command(pkt, CMDQ_CODE_WFE, event, arg_b); return cmdq_pkt_append_command(pkt, inst); } EXPORT_SYMBOL(cmdq_pkt_wfe); int cmdq_pkt_clear_event(struct cmdq_pkt *pkt, u16 event) { struct cmdq_instruction inst = { {0} }; if (event >= CMDQ_MAX_EVENT) return -EINVAL; return cmdq_pkt_append_command(pkt, CMDQ_CODE_WFE, event, CMDQ_WFE_UPDATE); inst.op = CMDQ_CODE_WFE; inst.value = CMDQ_WFE_UPDATE; inst.event = event; return cmdq_pkt_append_command(pkt, inst); } EXPORT_SYMBOL(cmdq_pkt_clear_event); int cmdq_pkt_poll(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value) { struct cmdq_instruction inst = { {0} }; int err; inst.op = CMDQ_CODE_POLL; inst.value = value; inst.offset = offset; inst.subsys = subsys; err = cmdq_pkt_append_command(pkt, inst); return err; } EXPORT_SYMBOL(cmdq_pkt_poll); int cmdq_pkt_poll_mask(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value, u32 mask) { struct cmdq_instruction inst = { {0} }; int err; inst.op = CMDQ_CODE_MASK; inst.mask = ~mask; err = cmdq_pkt_append_command(pkt, inst); if (err < 0) return err; offset = offset | CMDQ_POLL_ENABLE_MASK; err = cmdq_pkt_poll(pkt, subsys, offset, value); return err; } EXPORT_SYMBOL(cmdq_pkt_poll_mask); static int cmdq_pkt_finalize(struct cmdq_pkt *pkt) { struct cmdq_instruction inst = { {0} }; int err; /* insert EOC and generate IRQ for each command iteration */ err = cmdq_pkt_append_command(pkt, CMDQ_CODE_EOC, 0, CMDQ_EOC_IRQ_EN); inst.op = CMDQ_CODE_EOC; inst.value = CMDQ_EOC_IRQ_EN; err = cmdq_pkt_append_command(pkt, inst); if (err < 0) return err; /* JUMP to end */ err |= cmdq_pkt_append_command(pkt, CMDQ_CODE_JUMP, 0, CMDQ_JUMP_PASS); inst.op = CMDQ_CODE_JUMP; inst.value = CMDQ_JUMP_PASS; err = cmdq_pkt_append_command(pkt, inst); return err; } Loading
include/linux/mailbox/mtk-cmdq-mailbox.h +11 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,16 @@ #define CMDQ_WFE_WAIT BIT(15) #define CMDQ_WFE_WAIT_VALUE 0x1 /* * WFE arg_b * bit 0-11: wait value * bit 15: 1 - wait, 0 - no wait * bit 16-27: update value * bit 31: 1 - update, 0 - no update */ #define CMDQ_WFE_OPTION (CMDQ_WFE_UPDATE | CMDQ_WFE_WAIT | \ CMDQ_WFE_WAIT_VALUE) /** cmdq event maximum */ #define CMDQ_MAX_EVENT 0x3ff Loading @@ -45,6 +55,7 @@ enum cmdq_code { CMDQ_CODE_MASK = 0x02, CMDQ_CODE_WRITE = 0x04, CMDQ_CODE_POLL = 0x08, CMDQ_CODE_JUMP = 0x10, CMDQ_CODE_WFE = 0x20, CMDQ_CODE_EOC = 0x40, Loading
include/linux/soc/mediatek/mtk-cmdq.h +53 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,12 @@ struct cmdq_pkt; struct cmdq_client_reg { u8 subsys; u16 offset; u16 size; }; struct cmdq_client { spinlock_t lock; u32 pkt_cnt; Loading @@ -24,6 +30,21 @@ struct cmdq_client { u32 timeout_ms; /* in unit of microsecond */ }; /** * cmdq_dev_get_client_reg() - parse cmdq client reg from the device * node of CMDQ client * @dev: device of CMDQ mailbox client * @client_reg: CMDQ client reg pointer * @idx: the index of desired reg * * Return: 0 for success; else the error code is returned * * Help CMDQ client parsing the cmdq client reg * from the device node of CMDQ client. */ int cmdq_dev_get_client_reg(struct device *dev, struct cmdq_client_reg *client_reg, int idx); /** * cmdq_mbox_create() - create CMDQ mailbox client and channel * @dev: device of CMDQ mailbox client Loading Loading @@ -99,6 +120,38 @@ int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u16 event); */ int cmdq_pkt_clear_event(struct cmdq_pkt *pkt, u16 event); /** * cmdq_pkt_poll() - Append polling command to the CMDQ packet, ask GCE to * execute an instruction that wait for a specified * hardware register to check for the value w/o mask. * All GCE hardware threads will be blocked by this * instruction. * @pkt: the CMDQ packet * @subsys: the CMDQ sub system code * @offset: register offset from CMDQ sub system * @value: the specified target register value * * Return: 0 for success; else the error code is returned */ int cmdq_pkt_poll(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value); /** * cmdq_pkt_poll_mask() - Append polling command to the CMDQ packet, ask GCE to * execute an instruction that wait for a specified * hardware register to check for the value w/ mask. * All GCE hardware threads will be blocked by this * instruction. * @pkt: the CMDQ packet * @subsys: the CMDQ sub system code * @offset: register offset from CMDQ sub system * @value: the specified target register value * @mask: the specified target register mask * * Return: 0 for success; else the error code is returned */ int cmdq_pkt_poll_mask(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value, u32 mask); /** * cmdq_pkt_flush_async() - trigger CMDQ to asynchronously execute the CMDQ * packet and call back at the end of done packet Loading