1576f1b4bSHoulong Wei // SPDX-License-Identifier: GPL-2.0
2576f1b4bSHoulong Wei //
3576f1b4bSHoulong Wei // Copyright (c) 2018 MediaTek Inc.
4576f1b4bSHoulong Wei
5576f1b4bSHoulong Wei #include <linux/completion.h>
6576f1b4bSHoulong Wei #include <linux/errno.h>
7576f1b4bSHoulong Wei #include <linux/dma-mapping.h>
8576f1b4bSHoulong Wei #include <linux/module.h>
9576f1b4bSHoulong Wei #include <linux/mailbox_controller.h>
10d01e0aecSRob Herring #include <linux/of.h>
11576f1b4bSHoulong Wei #include <linux/soc/mediatek/mtk-cmdq.h>
12576f1b4bSHoulong Wei
13576f1b4bSHoulong Wei #define CMDQ_WRITE_ENABLE_MASK BIT(0)
14b2ff2356SBibby Hsieh #define CMDQ_POLL_ENABLE_MASK BIT(0)
15576f1b4bSHoulong Wei #define CMDQ_EOC_IRQ_EN BIT(0)
16613c2e2cSDennis YC Hsieh #define CMDQ_REG_TYPE 1
17*19e9452dSChun-Kuang Hu #define CMDQ_JUMP_RELATIVE 0
18*19e9452dSChun-Kuang Hu #define CMDQ_JUMP_ABSOLUTE 1
19576f1b4bSHoulong Wei
205c8b718cSBibby Hsieh struct cmdq_instruction {
215c8b718cSBibby Hsieh union {
225c8b718cSBibby Hsieh u32 value;
235c8b718cSBibby Hsieh u32 mask;
245f6e560cSDennis YC Hsieh struct {
255f6e560cSDennis YC Hsieh u16 arg_c;
265f6e560cSDennis YC Hsieh u16 src_reg;
275f6e560cSDennis YC Hsieh };
285c8b718cSBibby Hsieh };
295c8b718cSBibby Hsieh union {
305c8b718cSBibby Hsieh u16 offset;
315c8b718cSBibby Hsieh u16 event;
32613c2e2cSDennis YC Hsieh u16 reg_dst;
335c8b718cSBibby Hsieh };
34613c2e2cSDennis YC Hsieh union {
355c8b718cSBibby Hsieh u8 subsys;
36613c2e2cSDennis YC Hsieh struct {
37613c2e2cSDennis YC Hsieh u8 sop:5;
38613c2e2cSDennis YC Hsieh u8 arg_c_t:1;
39613c2e2cSDennis YC Hsieh u8 src_t:1;
40613c2e2cSDennis YC Hsieh u8 dst_t:1;
41613c2e2cSDennis YC Hsieh };
42613c2e2cSDennis YC Hsieh };
435c8b718cSBibby Hsieh u8 op;
445c8b718cSBibby Hsieh };
455c8b718cSBibby Hsieh
cmdq_dev_get_client_reg(struct device * dev,struct cmdq_client_reg * client_reg,int idx)46d412f18cSBibby Hsieh int cmdq_dev_get_client_reg(struct device *dev,
47d412f18cSBibby Hsieh struct cmdq_client_reg *client_reg, int idx)
48d412f18cSBibby Hsieh {
49d412f18cSBibby Hsieh struct of_phandle_args spec;
50d412f18cSBibby Hsieh int err;
51d412f18cSBibby Hsieh
52d412f18cSBibby Hsieh if (!client_reg)
53d412f18cSBibby Hsieh return -ENOENT;
54d412f18cSBibby Hsieh
55d412f18cSBibby Hsieh err = of_parse_phandle_with_fixed_args(dev->of_node,
56d412f18cSBibby Hsieh "mediatek,gce-client-reg",
57d412f18cSBibby Hsieh 3, idx, &spec);
58d412f18cSBibby Hsieh if (err < 0) {
59d412f18cSBibby Hsieh dev_err(dev,
60d412f18cSBibby Hsieh "error %d can't parse gce-client-reg property (%d)",
61d412f18cSBibby Hsieh err, idx);
62d412f18cSBibby Hsieh
63d412f18cSBibby Hsieh return err;
64d412f18cSBibby Hsieh }
65d412f18cSBibby Hsieh
66d412f18cSBibby Hsieh client_reg->subsys = (u8)spec.args[0];
67d412f18cSBibby Hsieh client_reg->offset = (u16)spec.args[1];
68d412f18cSBibby Hsieh client_reg->size = (u16)spec.args[2];
69d412f18cSBibby Hsieh of_node_put(spec.np);
70d412f18cSBibby Hsieh
71d412f18cSBibby Hsieh return 0;
72d412f18cSBibby Hsieh }
73d412f18cSBibby Hsieh EXPORT_SYMBOL(cmdq_dev_get_client_reg);
74d412f18cSBibby Hsieh
cmdq_mbox_create(struct device * dev,int index)75a69dcdfcSChun-Kuang Hu struct cmdq_client *cmdq_mbox_create(struct device *dev, int index)
76576f1b4bSHoulong Wei {
77576f1b4bSHoulong Wei struct cmdq_client *client;
78576f1b4bSHoulong Wei
79576f1b4bSHoulong Wei client = kzalloc(sizeof(*client), GFP_KERNEL);
80576f1b4bSHoulong Wei if (!client)
81576f1b4bSHoulong Wei return (struct cmdq_client *)-ENOMEM;
82576f1b4bSHoulong Wei
83576f1b4bSHoulong Wei client->client.dev = dev;
84576f1b4bSHoulong Wei client->client.tx_block = false;
85ce35e21dSBibby Hsieh client->client.knows_txdone = true;
86576f1b4bSHoulong Wei client->chan = mbox_request_channel(&client->client, index);
87576f1b4bSHoulong Wei
88576f1b4bSHoulong Wei if (IS_ERR(client->chan)) {
89576f1b4bSHoulong Wei long err;
90576f1b4bSHoulong Wei
91576f1b4bSHoulong Wei dev_err(dev, "failed to request channel\n");
92576f1b4bSHoulong Wei err = PTR_ERR(client->chan);
93576f1b4bSHoulong Wei kfree(client);
94576f1b4bSHoulong Wei
95576f1b4bSHoulong Wei return ERR_PTR(err);
96576f1b4bSHoulong Wei }
97576f1b4bSHoulong Wei
98576f1b4bSHoulong Wei return client;
99576f1b4bSHoulong Wei }
100576f1b4bSHoulong Wei EXPORT_SYMBOL(cmdq_mbox_create);
101576f1b4bSHoulong Wei
cmdq_mbox_destroy(struct cmdq_client * client)102576f1b4bSHoulong Wei void cmdq_mbox_destroy(struct cmdq_client *client)
103576f1b4bSHoulong Wei {
104576f1b4bSHoulong Wei mbox_free_channel(client->chan);
105576f1b4bSHoulong Wei kfree(client);
106576f1b4bSHoulong Wei }
107576f1b4bSHoulong Wei EXPORT_SYMBOL(cmdq_mbox_destroy);
108576f1b4bSHoulong Wei
cmdq_pkt_create(struct cmdq_client * client,size_t size)109576f1b4bSHoulong Wei struct cmdq_pkt *cmdq_pkt_create(struct cmdq_client *client, size_t size)
110576f1b4bSHoulong Wei {
111576f1b4bSHoulong Wei struct cmdq_pkt *pkt;
112576f1b4bSHoulong Wei struct device *dev;
113576f1b4bSHoulong Wei dma_addr_t dma_addr;
114576f1b4bSHoulong Wei
115576f1b4bSHoulong Wei pkt = kzalloc(sizeof(*pkt), GFP_KERNEL);
116576f1b4bSHoulong Wei if (!pkt)
117576f1b4bSHoulong Wei return ERR_PTR(-ENOMEM);
118576f1b4bSHoulong Wei pkt->va_base = kzalloc(size, GFP_KERNEL);
119576f1b4bSHoulong Wei if (!pkt->va_base) {
120576f1b4bSHoulong Wei kfree(pkt);
121576f1b4bSHoulong Wei return ERR_PTR(-ENOMEM);
122576f1b4bSHoulong Wei }
123576f1b4bSHoulong Wei pkt->buf_size = size;
124576f1b4bSHoulong Wei pkt->cl = (void *)client;
125576f1b4bSHoulong Wei
126576f1b4bSHoulong Wei dev = client->chan->mbox->dev;
127576f1b4bSHoulong Wei dma_addr = dma_map_single(dev, pkt->va_base, pkt->buf_size,
128576f1b4bSHoulong Wei DMA_TO_DEVICE);
129576f1b4bSHoulong Wei if (dma_mapping_error(dev, dma_addr)) {
130576f1b4bSHoulong Wei dev_err(dev, "dma map failed, size=%u\n", (u32)(u64)size);
131576f1b4bSHoulong Wei kfree(pkt->va_base);
132576f1b4bSHoulong Wei kfree(pkt);
133576f1b4bSHoulong Wei return ERR_PTR(-ENOMEM);
134576f1b4bSHoulong Wei }
135576f1b4bSHoulong Wei
136576f1b4bSHoulong Wei pkt->pa_base = dma_addr;
137576f1b4bSHoulong Wei
138576f1b4bSHoulong Wei return pkt;
139576f1b4bSHoulong Wei }
140576f1b4bSHoulong Wei EXPORT_SYMBOL(cmdq_pkt_create);
141576f1b4bSHoulong Wei
cmdq_pkt_destroy(struct cmdq_pkt * pkt)142576f1b4bSHoulong Wei void cmdq_pkt_destroy(struct cmdq_pkt *pkt)
143576f1b4bSHoulong Wei {
144576f1b4bSHoulong Wei struct cmdq_client *client = (struct cmdq_client *)pkt->cl;
145576f1b4bSHoulong Wei
146576f1b4bSHoulong Wei dma_unmap_single(client->chan->mbox->dev, pkt->pa_base, pkt->buf_size,
147576f1b4bSHoulong Wei DMA_TO_DEVICE);
148576f1b4bSHoulong Wei kfree(pkt->va_base);
149576f1b4bSHoulong Wei kfree(pkt);
150576f1b4bSHoulong Wei }
151576f1b4bSHoulong Wei EXPORT_SYMBOL(cmdq_pkt_destroy);
152576f1b4bSHoulong Wei
cmdq_pkt_append_command(struct cmdq_pkt * pkt,struct cmdq_instruction inst)1535c8b718cSBibby Hsieh static int cmdq_pkt_append_command(struct cmdq_pkt *pkt,
1545c8b718cSBibby Hsieh struct cmdq_instruction inst)
155576f1b4bSHoulong Wei {
1565c8b718cSBibby Hsieh struct cmdq_instruction *cmd_ptr;
157576f1b4bSHoulong Wei
158576f1b4bSHoulong Wei if (unlikely(pkt->cmd_buf_size + CMDQ_INST_SIZE > pkt->buf_size)) {
159576f1b4bSHoulong Wei /*
160576f1b4bSHoulong Wei * In the case of allocated buffer size (pkt->buf_size) is used
161576f1b4bSHoulong Wei * up, the real required size (pkt->cmdq_buf_size) is still
162576f1b4bSHoulong Wei * increased, so that the user knows how much memory should be
163576f1b4bSHoulong Wei * ultimately allocated after appending all commands and
164576f1b4bSHoulong Wei * flushing the command packet. Therefor, the user can call
165576f1b4bSHoulong Wei * cmdq_pkt_create() again with the real required buffer size.
166576f1b4bSHoulong Wei */
167576f1b4bSHoulong Wei pkt->cmd_buf_size += CMDQ_INST_SIZE;
168576f1b4bSHoulong Wei WARN_ONCE(1, "%s: buffer size %u is too small !\n",
169576f1b4bSHoulong Wei __func__, (u32)pkt->buf_size);
170576f1b4bSHoulong Wei return -ENOMEM;
171576f1b4bSHoulong Wei }
1725c8b718cSBibby Hsieh
173576f1b4bSHoulong Wei cmd_ptr = pkt->va_base + pkt->cmd_buf_size;
1745c8b718cSBibby Hsieh *cmd_ptr = inst;
175576f1b4bSHoulong Wei pkt->cmd_buf_size += CMDQ_INST_SIZE;
176576f1b4bSHoulong Wei
177576f1b4bSHoulong Wei return 0;
178576f1b4bSHoulong Wei }
179576f1b4bSHoulong Wei
cmdq_pkt_write(struct cmdq_pkt * pkt,u8 subsys,u16 offset,u32 value)180556030f0SBibby Hsieh int cmdq_pkt_write(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value)
181576f1b4bSHoulong Wei {
1825c8b718cSBibby Hsieh struct cmdq_instruction inst;
183576f1b4bSHoulong Wei
1845c8b718cSBibby Hsieh inst.op = CMDQ_CODE_WRITE;
1855c8b718cSBibby Hsieh inst.value = value;
1865c8b718cSBibby Hsieh inst.offset = offset;
1875c8b718cSBibby Hsieh inst.subsys = subsys;
1885c8b718cSBibby Hsieh
1895c8b718cSBibby Hsieh return cmdq_pkt_append_command(pkt, inst);
190576f1b4bSHoulong Wei }
191576f1b4bSHoulong Wei EXPORT_SYMBOL(cmdq_pkt_write);
192576f1b4bSHoulong Wei
cmdq_pkt_write_mask(struct cmdq_pkt * pkt,u8 subsys,u16 offset,u32 value,u32 mask)193556030f0SBibby Hsieh int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u8 subsys,
194556030f0SBibby Hsieh u16 offset, u32 value, u32 mask)
195576f1b4bSHoulong Wei {
1965c8b718cSBibby Hsieh struct cmdq_instruction inst = { {0} };
1975c8b718cSBibby Hsieh u16 offset_mask = offset;
19801d1b408SBibby Hsieh int err;
199576f1b4bSHoulong Wei
200576f1b4bSHoulong Wei if (mask != 0xffffffff) {
2015c8b718cSBibby Hsieh inst.op = CMDQ_CODE_MASK;
2025c8b718cSBibby Hsieh inst.mask = ~mask;
2035c8b718cSBibby Hsieh err = cmdq_pkt_append_command(pkt, inst);
20401d1b408SBibby Hsieh if (err < 0)
20501d1b408SBibby Hsieh return err;
20601d1b408SBibby Hsieh
207576f1b4bSHoulong Wei offset_mask |= CMDQ_WRITE_ENABLE_MASK;
208576f1b4bSHoulong Wei }
20901d1b408SBibby Hsieh err = cmdq_pkt_write(pkt, subsys, offset_mask, value);
210576f1b4bSHoulong Wei
211576f1b4bSHoulong Wei return err;
212576f1b4bSHoulong Wei }
213576f1b4bSHoulong Wei EXPORT_SYMBOL(cmdq_pkt_write_mask);
214576f1b4bSHoulong Wei
cmdq_pkt_read_s(struct cmdq_pkt * pkt,u16 high_addr_reg_idx,u16 addr_low,u16 reg_idx)215d3b04aabSDennis YC Hsieh int cmdq_pkt_read_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx, u16 addr_low,
216d3b04aabSDennis YC Hsieh u16 reg_idx)
217d3b04aabSDennis YC Hsieh {
218d3b04aabSDennis YC Hsieh struct cmdq_instruction inst = {};
219d3b04aabSDennis YC Hsieh
220d3b04aabSDennis YC Hsieh inst.op = CMDQ_CODE_READ_S;
221d3b04aabSDennis YC Hsieh inst.dst_t = CMDQ_REG_TYPE;
222d3b04aabSDennis YC Hsieh inst.sop = high_addr_reg_idx;
223d3b04aabSDennis YC Hsieh inst.reg_dst = reg_idx;
224d3b04aabSDennis YC Hsieh inst.src_reg = addr_low;
225d3b04aabSDennis YC Hsieh
226d3b04aabSDennis YC Hsieh return cmdq_pkt_append_command(pkt, inst);
227d3b04aabSDennis YC Hsieh }
228d3b04aabSDennis YC Hsieh EXPORT_SYMBOL(cmdq_pkt_read_s);
229d3b04aabSDennis YC Hsieh
cmdq_pkt_write_s(struct cmdq_pkt * pkt,u16 high_addr_reg_idx,u16 addr_low,u16 src_reg_idx)2305f6e560cSDennis YC Hsieh int cmdq_pkt_write_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx,
2315f6e560cSDennis YC Hsieh u16 addr_low, u16 src_reg_idx)
2325f6e560cSDennis YC Hsieh {
2335f6e560cSDennis YC Hsieh struct cmdq_instruction inst = {};
2345f6e560cSDennis YC Hsieh
2355f6e560cSDennis YC Hsieh inst.op = CMDQ_CODE_WRITE_S;
2365f6e560cSDennis YC Hsieh inst.src_t = CMDQ_REG_TYPE;
2375f6e560cSDennis YC Hsieh inst.sop = high_addr_reg_idx;
2385f6e560cSDennis YC Hsieh inst.offset = addr_low;
2395f6e560cSDennis YC Hsieh inst.src_reg = src_reg_idx;
2405f6e560cSDennis YC Hsieh
2415f6e560cSDennis YC Hsieh return cmdq_pkt_append_command(pkt, inst);
2425f6e560cSDennis YC Hsieh }
2435f6e560cSDennis YC Hsieh EXPORT_SYMBOL(cmdq_pkt_write_s);
2445f6e560cSDennis YC Hsieh
cmdq_pkt_write_s_mask(struct cmdq_pkt * pkt,u16 high_addr_reg_idx,u16 addr_low,u16 src_reg_idx,u32 mask)24511c7842dSDennis YC Hsieh int cmdq_pkt_write_s_mask(struct cmdq_pkt *pkt, u16 high_addr_reg_idx,
24611c7842dSDennis YC Hsieh u16 addr_low, u16 src_reg_idx, u32 mask)
24711c7842dSDennis YC Hsieh {
24811c7842dSDennis YC Hsieh struct cmdq_instruction inst = {};
24911c7842dSDennis YC Hsieh int err;
25011c7842dSDennis YC Hsieh
25111c7842dSDennis YC Hsieh inst.op = CMDQ_CODE_MASK;
25211c7842dSDennis YC Hsieh inst.mask = ~mask;
25311c7842dSDennis YC Hsieh err = cmdq_pkt_append_command(pkt, inst);
25411c7842dSDennis YC Hsieh if (err < 0)
25511c7842dSDennis YC Hsieh return err;
25611c7842dSDennis YC Hsieh
25711c7842dSDennis YC Hsieh inst.mask = 0;
25811c7842dSDennis YC Hsieh inst.op = CMDQ_CODE_WRITE_S_MASK;
25911c7842dSDennis YC Hsieh inst.src_t = CMDQ_REG_TYPE;
26011c7842dSDennis YC Hsieh inst.sop = high_addr_reg_idx;
26111c7842dSDennis YC Hsieh inst.offset = addr_low;
26211c7842dSDennis YC Hsieh inst.src_reg = src_reg_idx;
26311c7842dSDennis YC Hsieh
26411c7842dSDennis YC Hsieh return cmdq_pkt_append_command(pkt, inst);
26511c7842dSDennis YC Hsieh }
26611c7842dSDennis YC Hsieh EXPORT_SYMBOL(cmdq_pkt_write_s_mask);
26711c7842dSDennis YC Hsieh
cmdq_pkt_write_s_value(struct cmdq_pkt * pkt,u8 high_addr_reg_idx,u16 addr_low,u32 value)2681af43fceSDennis YC Hsieh int cmdq_pkt_write_s_value(struct cmdq_pkt *pkt, u8 high_addr_reg_idx,
2691af43fceSDennis YC Hsieh u16 addr_low, u32 value)
2701af43fceSDennis YC Hsieh {
2711af43fceSDennis YC Hsieh struct cmdq_instruction inst = {};
2721af43fceSDennis YC Hsieh
2731af43fceSDennis YC Hsieh inst.op = CMDQ_CODE_WRITE_S;
2741af43fceSDennis YC Hsieh inst.sop = high_addr_reg_idx;
2751af43fceSDennis YC Hsieh inst.offset = addr_low;
2761af43fceSDennis YC Hsieh inst.value = value;
2771af43fceSDennis YC Hsieh
2781af43fceSDennis YC Hsieh return cmdq_pkt_append_command(pkt, inst);
2791af43fceSDennis YC Hsieh }
2801af43fceSDennis YC Hsieh EXPORT_SYMBOL(cmdq_pkt_write_s_value);
2811af43fceSDennis YC Hsieh
cmdq_pkt_write_s_mask_value(struct cmdq_pkt * pkt,u8 high_addr_reg_idx,u16 addr_low,u32 value,u32 mask)28288a2ffc4SDennis YC Hsieh int cmdq_pkt_write_s_mask_value(struct cmdq_pkt *pkt, u8 high_addr_reg_idx,
28388a2ffc4SDennis YC Hsieh u16 addr_low, u32 value, u32 mask)
28488a2ffc4SDennis YC Hsieh {
28588a2ffc4SDennis YC Hsieh struct cmdq_instruction inst = {};
28688a2ffc4SDennis YC Hsieh int err;
28788a2ffc4SDennis YC Hsieh
28888a2ffc4SDennis YC Hsieh inst.op = CMDQ_CODE_MASK;
28988a2ffc4SDennis YC Hsieh inst.mask = ~mask;
29088a2ffc4SDennis YC Hsieh err = cmdq_pkt_append_command(pkt, inst);
29188a2ffc4SDennis YC Hsieh if (err < 0)
29288a2ffc4SDennis YC Hsieh return err;
29388a2ffc4SDennis YC Hsieh
29488a2ffc4SDennis YC Hsieh inst.op = CMDQ_CODE_WRITE_S_MASK;
29588a2ffc4SDennis YC Hsieh inst.sop = high_addr_reg_idx;
29688a2ffc4SDennis YC Hsieh inst.offset = addr_low;
29788a2ffc4SDennis YC Hsieh inst.value = value;
29888a2ffc4SDennis YC Hsieh
29988a2ffc4SDennis YC Hsieh return cmdq_pkt_append_command(pkt, inst);
30088a2ffc4SDennis YC Hsieh }
30188a2ffc4SDennis YC Hsieh EXPORT_SYMBOL(cmdq_pkt_write_s_mask_value);
30288a2ffc4SDennis YC Hsieh
cmdq_pkt_wfe(struct cmdq_pkt * pkt,u16 event,bool clear)30323c22299SDennis YC Hsieh int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u16 event, bool clear)
304576f1b4bSHoulong Wei {
3055c8b718cSBibby Hsieh struct cmdq_instruction inst = { {0} };
30623c22299SDennis YC Hsieh u32 clear_option = clear ? CMDQ_WFE_UPDATE : 0;
307576f1b4bSHoulong Wei
308576f1b4bSHoulong Wei if (event >= CMDQ_MAX_EVENT)
309576f1b4bSHoulong Wei return -EINVAL;
310576f1b4bSHoulong Wei
3115c8b718cSBibby Hsieh inst.op = CMDQ_CODE_WFE;
31223c22299SDennis YC Hsieh inst.value = CMDQ_WFE_OPTION | clear_option;
3135c8b718cSBibby Hsieh inst.event = event;
314576f1b4bSHoulong Wei
3155c8b718cSBibby Hsieh return cmdq_pkt_append_command(pkt, inst);
316576f1b4bSHoulong Wei }
317576f1b4bSHoulong Wei EXPORT_SYMBOL(cmdq_pkt_wfe);
318576f1b4bSHoulong Wei
cmdq_pkt_clear_event(struct cmdq_pkt * pkt,u16 event)319556030f0SBibby Hsieh int cmdq_pkt_clear_event(struct cmdq_pkt *pkt, u16 event)
320576f1b4bSHoulong Wei {
3215c8b718cSBibby Hsieh struct cmdq_instruction inst = { {0} };
3225c8b718cSBibby Hsieh
323576f1b4bSHoulong Wei if (event >= CMDQ_MAX_EVENT)
324576f1b4bSHoulong Wei return -EINVAL;
325576f1b4bSHoulong Wei
3265c8b718cSBibby Hsieh inst.op = CMDQ_CODE_WFE;
3275c8b718cSBibby Hsieh inst.value = CMDQ_WFE_UPDATE;
3285c8b718cSBibby Hsieh inst.event = event;
3295c8b718cSBibby Hsieh
3305c8b718cSBibby Hsieh return cmdq_pkt_append_command(pkt, inst);
331576f1b4bSHoulong Wei }
332576f1b4bSHoulong Wei EXPORT_SYMBOL(cmdq_pkt_clear_event);
333576f1b4bSHoulong Wei
cmdq_pkt_set_event(struct cmdq_pkt * pkt,u16 event)3347de796caSDennis YC Hsieh int cmdq_pkt_set_event(struct cmdq_pkt *pkt, u16 event)
3357de796caSDennis YC Hsieh {
3367de796caSDennis YC Hsieh struct cmdq_instruction inst = {};
3377de796caSDennis YC Hsieh
3387de796caSDennis YC Hsieh if (event >= CMDQ_MAX_EVENT)
3397de796caSDennis YC Hsieh return -EINVAL;
3407de796caSDennis YC Hsieh
3417de796caSDennis YC Hsieh inst.op = CMDQ_CODE_WFE;
3427de796caSDennis YC Hsieh inst.value = CMDQ_WFE_UPDATE | CMDQ_WFE_UPDATE_VALUE;
3437de796caSDennis YC Hsieh inst.event = event;
3447de796caSDennis YC Hsieh
3457de796caSDennis YC Hsieh return cmdq_pkt_append_command(pkt, inst);
3467de796caSDennis YC Hsieh }
3477de796caSDennis YC Hsieh EXPORT_SYMBOL(cmdq_pkt_set_event);
3487de796caSDennis YC Hsieh
cmdq_pkt_poll(struct cmdq_pkt * pkt,u8 subsys,u16 offset,u32 value)349b2ff2356SBibby Hsieh int cmdq_pkt_poll(struct cmdq_pkt *pkt, u8 subsys,
350b2ff2356SBibby Hsieh u16 offset, u32 value)
351b2ff2356SBibby Hsieh {
352b2ff2356SBibby Hsieh struct cmdq_instruction inst = { {0} };
353b2ff2356SBibby Hsieh int err;
354b2ff2356SBibby Hsieh
355b2ff2356SBibby Hsieh inst.op = CMDQ_CODE_POLL;
356b2ff2356SBibby Hsieh inst.value = value;
357b2ff2356SBibby Hsieh inst.offset = offset;
358b2ff2356SBibby Hsieh inst.subsys = subsys;
359b2ff2356SBibby Hsieh err = cmdq_pkt_append_command(pkt, inst);
360b2ff2356SBibby Hsieh
361b2ff2356SBibby Hsieh return err;
362b2ff2356SBibby Hsieh }
363b2ff2356SBibby Hsieh EXPORT_SYMBOL(cmdq_pkt_poll);
364b2ff2356SBibby Hsieh
cmdq_pkt_poll_mask(struct cmdq_pkt * pkt,u8 subsys,u16 offset,u32 value,u32 mask)365b2ff2356SBibby Hsieh int cmdq_pkt_poll_mask(struct cmdq_pkt *pkt, u8 subsys,
366b2ff2356SBibby Hsieh u16 offset, u32 value, u32 mask)
367b2ff2356SBibby Hsieh {
368b2ff2356SBibby Hsieh struct cmdq_instruction inst = { {0} };
369b2ff2356SBibby Hsieh int err;
370b2ff2356SBibby Hsieh
371b2ff2356SBibby Hsieh inst.op = CMDQ_CODE_MASK;
372b2ff2356SBibby Hsieh inst.mask = ~mask;
373b2ff2356SBibby Hsieh err = cmdq_pkt_append_command(pkt, inst);
374b2ff2356SBibby Hsieh if (err < 0)
375b2ff2356SBibby Hsieh return err;
376b2ff2356SBibby Hsieh
377b2ff2356SBibby Hsieh offset = offset | CMDQ_POLL_ENABLE_MASK;
378b2ff2356SBibby Hsieh err = cmdq_pkt_poll(pkt, subsys, offset, value);
379b2ff2356SBibby Hsieh
380b2ff2356SBibby Hsieh return err;
381b2ff2356SBibby Hsieh }
382b2ff2356SBibby Hsieh EXPORT_SYMBOL(cmdq_pkt_poll_mask);
383b2ff2356SBibby Hsieh
cmdq_pkt_assign(struct cmdq_pkt * pkt,u16 reg_idx,u32 value)384613c2e2cSDennis YC Hsieh int cmdq_pkt_assign(struct cmdq_pkt *pkt, u16 reg_idx, u32 value)
385613c2e2cSDennis YC Hsieh {
386613c2e2cSDennis YC Hsieh struct cmdq_instruction inst = {};
387613c2e2cSDennis YC Hsieh
388613c2e2cSDennis YC Hsieh inst.op = CMDQ_CODE_LOGIC;
389613c2e2cSDennis YC Hsieh inst.dst_t = CMDQ_REG_TYPE;
390613c2e2cSDennis YC Hsieh inst.reg_dst = reg_idx;
391613c2e2cSDennis YC Hsieh inst.value = value;
392613c2e2cSDennis YC Hsieh return cmdq_pkt_append_command(pkt, inst);
393613c2e2cSDennis YC Hsieh }
394613c2e2cSDennis YC Hsieh EXPORT_SYMBOL(cmdq_pkt_assign);
395613c2e2cSDennis YC Hsieh
cmdq_pkt_jump(struct cmdq_pkt * pkt,dma_addr_t addr)396946f1792SDennis YC Hsieh int cmdq_pkt_jump(struct cmdq_pkt *pkt, dma_addr_t addr)
397946f1792SDennis YC Hsieh {
398946f1792SDennis YC Hsieh struct cmdq_instruction inst = {};
399946f1792SDennis YC Hsieh
400946f1792SDennis YC Hsieh inst.op = CMDQ_CODE_JUMP;
401*19e9452dSChun-Kuang Hu inst.offset = CMDQ_JUMP_ABSOLUTE;
402946f1792SDennis YC Hsieh inst.value = addr >>
403946f1792SDennis YC Hsieh cmdq_get_shift_pa(((struct cmdq_client *)pkt->cl)->chan);
404946f1792SDennis YC Hsieh return cmdq_pkt_append_command(pkt, inst);
405946f1792SDennis YC Hsieh }
406946f1792SDennis YC Hsieh EXPORT_SYMBOL(cmdq_pkt_jump);
407946f1792SDennis YC Hsieh
cmdq_pkt_finalize(struct cmdq_pkt * pkt)40899581858SDennis YC Hsieh int cmdq_pkt_finalize(struct cmdq_pkt *pkt)
409576f1b4bSHoulong Wei {
4105c8b718cSBibby Hsieh struct cmdq_instruction inst = { {0} };
411576f1b4bSHoulong Wei int err;
412576f1b4bSHoulong Wei
413576f1b4bSHoulong Wei /* insert EOC and generate IRQ for each command iteration */
4145c8b718cSBibby Hsieh inst.op = CMDQ_CODE_EOC;
4155c8b718cSBibby Hsieh inst.value = CMDQ_EOC_IRQ_EN;
4165c8b718cSBibby Hsieh err = cmdq_pkt_append_command(pkt, inst);
41701d1b408SBibby Hsieh if (err < 0)
41801d1b408SBibby Hsieh return err;
419576f1b4bSHoulong Wei
420576f1b4bSHoulong Wei /* JUMP to end */
4215c8b718cSBibby Hsieh inst.op = CMDQ_CODE_JUMP;
4222b8cf383SDennis YC Hsieh inst.value = CMDQ_JUMP_PASS >>
4232b8cf383SDennis YC Hsieh cmdq_get_shift_pa(((struct cmdq_client *)pkt->cl)->chan);
4245c8b718cSBibby Hsieh err = cmdq_pkt_append_command(pkt, inst);
425576f1b4bSHoulong Wei
426576f1b4bSHoulong Wei return err;
427576f1b4bSHoulong Wei }
42899581858SDennis YC Hsieh EXPORT_SYMBOL(cmdq_pkt_finalize);
429576f1b4bSHoulong Wei
cmdq_pkt_flush_async(struct cmdq_pkt * pkt)4305252c1c5SChun-Kuang Hu int cmdq_pkt_flush_async(struct cmdq_pkt *pkt)
431576f1b4bSHoulong Wei {
432576f1b4bSHoulong Wei int err;
433576f1b4bSHoulong Wei struct cmdq_client *client = (struct cmdq_client *)pkt->cl;
434576f1b4bSHoulong Wei
43534c4e407SDennis YC Hsieh err = mbox_send_message(client->chan, pkt);
43634c4e407SDennis YC Hsieh if (err < 0)
43734c4e407SDennis YC Hsieh return err;
438576f1b4bSHoulong Wei /* We can send next packet immediately, so just call txdone. */
439576f1b4bSHoulong Wei mbox_client_txdone(client->chan, 0);
440576f1b4bSHoulong Wei
441576f1b4bSHoulong Wei return 0;
442576f1b4bSHoulong Wei }
443576f1b4bSHoulong Wei EXPORT_SYMBOL(cmdq_pkt_flush_async);
444576f1b4bSHoulong Wei
445576f1b4bSHoulong Wei MODULE_LICENSE("GPL v2");
446