Commit | Line | Data |
---|---|---|
576f1b4b HW |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // | |
3 | // Copyright (c) 2018 MediaTek Inc. | |
4 | ||
5 | #include <linux/completion.h> | |
6 | #include <linux/errno.h> | |
7 | #include <linux/dma-mapping.h> | |
8 | #include <linux/module.h> | |
9 | #include <linux/mailbox_controller.h> | |
d01e0aec | 10 | #include <linux/of.h> |
576f1b4b HW |
11 | #include <linux/soc/mediatek/mtk-cmdq.h> |
12 | ||
576f1b4b | 13 | #define CMDQ_WRITE_ENABLE_MASK BIT(0) |
b2ff2356 | 14 | #define CMDQ_POLL_ENABLE_MASK BIT(0) |
400e2fa8 JJL |
15 | /* dedicate the last GPR_R15 to assign the register address to be poll */ |
16 | #define CMDQ_POLL_ADDR_GPR (15) | |
576f1b4b | 17 | #define CMDQ_EOC_IRQ_EN BIT(0) |
58de63dd | 18 | #define CMDQ_IMMEDIATE_VALUE 0 |
613c2e2c | 19 | #define CMDQ_REG_TYPE 1 |
ed4d5ab1 CKH |
20 | #define CMDQ_JUMP_RELATIVE 0 |
21 | #define CMDQ_JUMP_ABSOLUTE 1 | |
576f1b4b | 22 | |
5c8b718c BH |
23 | struct cmdq_instruction { |
24 | union { | |
25 | u32 value; | |
26 | u32 mask; | |
5f6e560c DYH |
27 | struct { |
28 | u16 arg_c; | |
29 | u16 src_reg; | |
30 | }; | |
5c8b718c BH |
31 | }; |
32 | union { | |
33 | u16 offset; | |
34 | u16 event; | |
613c2e2c DYH |
35 | u16 reg_dst; |
36 | }; | |
37 | union { | |
38 | u8 subsys; | |
39 | struct { | |
40 | u8 sop:5; | |
41 | u8 arg_c_t:1; | |
42 | u8 src_t:1; | |
43 | u8 dst_t:1; | |
44 | }; | |
5c8b718c | 45 | }; |
5c8b718c BH |
46 | u8 op; |
47 | }; | |
48 | ||
58de63dd JJL |
49 | static inline u8 cmdq_operand_get_type(struct cmdq_operand *op) |
50 | { | |
51 | return op->reg ? CMDQ_REG_TYPE : CMDQ_IMMEDIATE_VALUE; | |
52 | } | |
53 | ||
54 | static inline u16 cmdq_operand_get_idx_value(struct cmdq_operand *op) | |
55 | { | |
56 | return op->reg ? op->idx : op->value; | |
57 | } | |
58 | ||
d412f18c BH |
59 | int cmdq_dev_get_client_reg(struct device *dev, |
60 | struct cmdq_client_reg *client_reg, int idx) | |
61 | { | |
62 | struct of_phandle_args spec; | |
63 | int err; | |
64 | ||
65 | if (!client_reg) | |
66 | return -ENOENT; | |
67 | ||
68 | err = of_parse_phandle_with_fixed_args(dev->of_node, | |
69 | "mediatek,gce-client-reg", | |
70 | 3, idx, &spec); | |
71 | if (err < 0) { | |
27e69538 | 72 | dev_warn(dev, |
d412f18c BH |
73 | "error %d can't parse gce-client-reg property (%d)", |
74 | err, idx); | |
75 | ||
76 | return err; | |
77 | } | |
78 | ||
79 | client_reg->subsys = (u8)spec.args[0]; | |
80 | client_reg->offset = (u16)spec.args[1]; | |
81 | client_reg->size = (u16)spec.args[2]; | |
82 | of_node_put(spec.np); | |
83 | ||
84 | return 0; | |
85 | } | |
86 | EXPORT_SYMBOL(cmdq_dev_get_client_reg); | |
87 | ||
a69dcdfc | 88 | struct cmdq_client *cmdq_mbox_create(struct device *dev, int index) |
576f1b4b HW |
89 | { |
90 | struct cmdq_client *client; | |
91 | ||
92 | client = kzalloc(sizeof(*client), GFP_KERNEL); | |
93 | if (!client) | |
94 | return (struct cmdq_client *)-ENOMEM; | |
95 | ||
576f1b4b HW |
96 | client->client.dev = dev; |
97 | client->client.tx_block = false; | |
ce35e21d | 98 | client->client.knows_txdone = true; |
576f1b4b HW |
99 | client->chan = mbox_request_channel(&client->client, index); |
100 | ||
101 | if (IS_ERR(client->chan)) { | |
102 | long err; | |
103 | ||
104 | dev_err(dev, "failed to request channel\n"); | |
105 | err = PTR_ERR(client->chan); | |
106 | kfree(client); | |
107 | ||
108 | return ERR_PTR(err); | |
109 | } | |
110 | ||
111 | return client; | |
112 | } | |
113 | EXPORT_SYMBOL(cmdq_mbox_create); | |
114 | ||
115 | void cmdq_mbox_destroy(struct cmdq_client *client) | |
116 | { | |
576f1b4b HW |
117 | mbox_free_channel(client->chan); |
118 | kfree(client); | |
119 | } | |
120 | EXPORT_SYMBOL(cmdq_mbox_destroy); | |
121 | ||
b81b2d55 | 122 | int cmdq_pkt_create(struct cmdq_client *client, struct cmdq_pkt *pkt, size_t size) |
576f1b4b | 123 | { |
576f1b4b HW |
124 | struct device *dev; |
125 | dma_addr_t dma_addr; | |
126 | ||
576f1b4b | 127 | pkt->va_base = kzalloc(size, GFP_KERNEL); |
b81b2d55 CKH |
128 | if (!pkt->va_base) |
129 | return -ENOMEM; | |
130 | ||
576f1b4b | 131 | pkt->buf_size = size; |
576f1b4b HW |
132 | |
133 | dev = client->chan->mbox->dev; | |
134 | dma_addr = dma_map_single(dev, pkt->va_base, pkt->buf_size, | |
135 | DMA_TO_DEVICE); | |
136 | if (dma_mapping_error(dev, dma_addr)) { | |
137 | dev_err(dev, "dma map failed, size=%u\n", (u32)(u64)size); | |
138 | kfree(pkt->va_base); | |
b81b2d55 | 139 | return -ENOMEM; |
576f1b4b HW |
140 | } |
141 | ||
142 | pkt->pa_base = dma_addr; | |
143 | ||
b81b2d55 | 144 | return 0; |
576f1b4b HW |
145 | } |
146 | EXPORT_SYMBOL(cmdq_pkt_create); | |
147 | ||
b81b2d55 | 148 | void cmdq_pkt_destroy(struct cmdq_client *client, struct cmdq_pkt *pkt) |
576f1b4b | 149 | { |
576f1b4b HW |
150 | dma_unmap_single(client->chan->mbox->dev, pkt->pa_base, pkt->buf_size, |
151 | DMA_TO_DEVICE); | |
152 | kfree(pkt->va_base); | |
576f1b4b HW |
153 | } |
154 | EXPORT_SYMBOL(cmdq_pkt_destroy); | |
155 | ||
5c8b718c BH |
156 | static int cmdq_pkt_append_command(struct cmdq_pkt *pkt, |
157 | struct cmdq_instruction inst) | |
576f1b4b | 158 | { |
5c8b718c | 159 | struct cmdq_instruction *cmd_ptr; |
576f1b4b HW |
160 | |
161 | if (unlikely(pkt->cmd_buf_size + CMDQ_INST_SIZE > pkt->buf_size)) { | |
162 | /* | |
163 | * In the case of allocated buffer size (pkt->buf_size) is used | |
164 | * up, the real required size (pkt->cmdq_buf_size) is still | |
165 | * increased, so that the user knows how much memory should be | |
166 | * ultimately allocated after appending all commands and | |
167 | * flushing the command packet. Therefor, the user can call | |
168 | * cmdq_pkt_create() again with the real required buffer size. | |
169 | */ | |
170 | pkt->cmd_buf_size += CMDQ_INST_SIZE; | |
171 | WARN_ONCE(1, "%s: buffer size %u is too small !\n", | |
172 | __func__, (u32)pkt->buf_size); | |
173 | return -ENOMEM; | |
174 | } | |
5c8b718c | 175 | |
576f1b4b | 176 | cmd_ptr = pkt->va_base + pkt->cmd_buf_size; |
5c8b718c | 177 | *cmd_ptr = inst; |
576f1b4b HW |
178 | pkt->cmd_buf_size += CMDQ_INST_SIZE; |
179 | ||
180 | return 0; | |
181 | } | |
182 | ||
4b334721 ADR |
183 | static int cmdq_pkt_mask(struct cmdq_pkt *pkt, u32 mask) |
184 | { | |
185 | struct cmdq_instruction inst = { | |
186 | .op = CMDQ_CODE_MASK, | |
187 | .mask = ~mask | |
188 | }; | |
189 | return cmdq_pkt_append_command(pkt, inst); | |
190 | } | |
191 | ||
556030f0 | 192 | int cmdq_pkt_write(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value) |
576f1b4b | 193 | { |
34771841 ADR |
194 | struct cmdq_instruction inst = { |
195 | .op = CMDQ_CODE_WRITE, | |
196 | .value = value, | |
197 | .offset = offset, | |
198 | .subsys = subsys | |
199 | }; | |
5c8b718c | 200 | return cmdq_pkt_append_command(pkt, inst); |
576f1b4b HW |
201 | } |
202 | EXPORT_SYMBOL(cmdq_pkt_write); | |
203 | ||
556030f0 BH |
204 | int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u8 subsys, |
205 | u16 offset, u32 value, u32 mask) | |
576f1b4b | 206 | { |
5c8b718c | 207 | u16 offset_mask = offset; |
01d1b408 | 208 | int err; |
576f1b4b | 209 | |
34771841 | 210 | if (mask != GENMASK(31, 0)) { |
4b334721 | 211 | err = cmdq_pkt_mask(pkt, mask); |
01d1b408 BH |
212 | if (err < 0) |
213 | return err; | |
214 | ||
576f1b4b HW |
215 | offset_mask |= CMDQ_WRITE_ENABLE_MASK; |
216 | } | |
34771841 | 217 | return cmdq_pkt_write(pkt, subsys, offset_mask, value); |
576f1b4b HW |
218 | } |
219 | EXPORT_SYMBOL(cmdq_pkt_write_mask); | |
220 | ||
d3b04aab DYH |
221 | int cmdq_pkt_read_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx, u16 addr_low, |
222 | u16 reg_idx) | |
223 | { | |
34771841 ADR |
224 | struct cmdq_instruction inst = { |
225 | .op = CMDQ_CODE_READ_S, | |
226 | .dst_t = CMDQ_REG_TYPE, | |
227 | .sop = high_addr_reg_idx, | |
228 | .reg_dst = reg_idx, | |
229 | .src_reg = addr_low | |
230 | }; | |
d3b04aab DYH |
231 | return cmdq_pkt_append_command(pkt, inst); |
232 | } | |
233 | EXPORT_SYMBOL(cmdq_pkt_read_s); | |
234 | ||
5f6e560c DYH |
235 | int cmdq_pkt_write_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx, |
236 | u16 addr_low, u16 src_reg_idx) | |
237 | { | |
34771841 ADR |
238 | struct cmdq_instruction inst = { |
239 | .op = CMDQ_CODE_WRITE_S, | |
240 | .src_t = CMDQ_REG_TYPE, | |
241 | .sop = high_addr_reg_idx, | |
242 | .offset = addr_low, | |
243 | .src_reg = src_reg_idx | |
244 | }; | |
5f6e560c DYH |
245 | return cmdq_pkt_append_command(pkt, inst); |
246 | } | |
247 | EXPORT_SYMBOL(cmdq_pkt_write_s); | |
248 | ||
11c7842d DYH |
249 | int cmdq_pkt_write_s_mask(struct cmdq_pkt *pkt, u16 high_addr_reg_idx, |
250 | u16 addr_low, u16 src_reg_idx, u32 mask) | |
251 | { | |
34771841 ADR |
252 | struct cmdq_instruction inst = { |
253 | .op = CMDQ_CODE_WRITE_S_MASK, | |
254 | .src_t = CMDQ_REG_TYPE, | |
255 | .sop = high_addr_reg_idx, | |
256 | .offset = addr_low, | |
257 | .src_reg = src_reg_idx, | |
258 | }; | |
11c7842d DYH |
259 | int err; |
260 | ||
4b334721 | 261 | err = cmdq_pkt_mask(pkt, mask); |
11c7842d DYH |
262 | if (err < 0) |
263 | return err; | |
264 | ||
11c7842d DYH |
265 | return cmdq_pkt_append_command(pkt, inst); |
266 | } | |
267 | EXPORT_SYMBOL(cmdq_pkt_write_s_mask); | |
268 | ||
1af43fce DYH |
269 | int cmdq_pkt_write_s_value(struct cmdq_pkt *pkt, u8 high_addr_reg_idx, |
270 | u16 addr_low, u32 value) | |
271 | { | |
34771841 ADR |
272 | struct cmdq_instruction inst = { |
273 | .op = CMDQ_CODE_WRITE_S, | |
274 | .sop = high_addr_reg_idx, | |
275 | .offset = addr_low, | |
276 | .value = value | |
277 | }; | |
1af43fce DYH |
278 | return cmdq_pkt_append_command(pkt, inst); |
279 | } | |
280 | EXPORT_SYMBOL(cmdq_pkt_write_s_value); | |
281 | ||
88a2ffc4 DYH |
282 | int cmdq_pkt_write_s_mask_value(struct cmdq_pkt *pkt, u8 high_addr_reg_idx, |
283 | u16 addr_low, u32 value, u32 mask) | |
284 | { | |
34771841 ADR |
285 | struct cmdq_instruction inst = { |
286 | .op = CMDQ_CODE_WRITE_S_MASK, | |
287 | .sop = high_addr_reg_idx, | |
288 | .offset = addr_low, | |
289 | .value = value | |
290 | }; | |
88a2ffc4 DYH |
291 | int err; |
292 | ||
4b334721 | 293 | err = cmdq_pkt_mask(pkt, mask); |
88a2ffc4 DYH |
294 | if (err < 0) |
295 | return err; | |
296 | ||
88a2ffc4 DYH |
297 | return cmdq_pkt_append_command(pkt, inst); |
298 | } | |
299 | EXPORT_SYMBOL(cmdq_pkt_write_s_mask_value); | |
300 | ||
263801f8 JJL |
301 | int cmdq_pkt_mem_move(struct cmdq_pkt *pkt, dma_addr_t src_addr, dma_addr_t dst_addr) |
302 | { | |
303 | const u16 high_addr_reg_idx = CMDQ_THR_SPR_IDX0; | |
304 | const u16 value_reg_idx = CMDQ_THR_SPR_IDX1; | |
305 | int ret; | |
306 | ||
307 | /* read the value of src_addr into high_addr_reg_idx */ | |
308 | ret = cmdq_pkt_assign(pkt, high_addr_reg_idx, CMDQ_ADDR_HIGH(src_addr)); | |
309 | if (ret < 0) | |
310 | return ret; | |
311 | ret = cmdq_pkt_read_s(pkt, high_addr_reg_idx, CMDQ_ADDR_LOW(src_addr), value_reg_idx); | |
312 | if (ret < 0) | |
313 | return ret; | |
314 | ||
315 | /* write the value of value_reg_idx into dst_addr */ | |
316 | ret = cmdq_pkt_assign(pkt, high_addr_reg_idx, CMDQ_ADDR_HIGH(dst_addr)); | |
317 | if (ret < 0) | |
318 | return ret; | |
319 | ret = cmdq_pkt_write_s(pkt, high_addr_reg_idx, CMDQ_ADDR_LOW(dst_addr), value_reg_idx); | |
320 | if (ret < 0) | |
321 | return ret; | |
322 | ||
323 | return 0; | |
324 | } | |
325 | EXPORT_SYMBOL(cmdq_pkt_mem_move); | |
326 | ||
23c22299 | 327 | int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u16 event, bool clear) |
576f1b4b | 328 | { |
23c22299 | 329 | u32 clear_option = clear ? CMDQ_WFE_UPDATE : 0; |
34771841 ADR |
330 | struct cmdq_instruction inst = { |
331 | .op = CMDQ_CODE_WFE, | |
332 | .value = CMDQ_WFE_OPTION | clear_option, | |
333 | .event = event | |
334 | }; | |
576f1b4b HW |
335 | |
336 | if (event >= CMDQ_MAX_EVENT) | |
337 | return -EINVAL; | |
338 | ||
5c8b718c | 339 | return cmdq_pkt_append_command(pkt, inst); |
576f1b4b HW |
340 | } |
341 | EXPORT_SYMBOL(cmdq_pkt_wfe); | |
342 | ||
69ff6833 JJL |
343 | int cmdq_pkt_acquire_event(struct cmdq_pkt *pkt, u16 event) |
344 | { | |
34771841 ADR |
345 | struct cmdq_instruction inst = { |
346 | .op = CMDQ_CODE_WFE, | |
347 | .value = CMDQ_WFE_UPDATE | CMDQ_WFE_UPDATE_VALUE | CMDQ_WFE_WAIT, | |
348 | .event = event | |
349 | }; | |
69ff6833 JJL |
350 | |
351 | if (event >= CMDQ_MAX_EVENT) | |
352 | return -EINVAL; | |
353 | ||
69ff6833 JJL |
354 | return cmdq_pkt_append_command(pkt, inst); |
355 | } | |
356 | EXPORT_SYMBOL(cmdq_pkt_acquire_event); | |
357 | ||
556030f0 | 358 | int cmdq_pkt_clear_event(struct cmdq_pkt *pkt, u16 event) |
576f1b4b | 359 | { |
34771841 ADR |
360 | struct cmdq_instruction inst = { |
361 | .op = CMDQ_CODE_WFE, | |
362 | .value = CMDQ_WFE_UPDATE, | |
363 | .event = event | |
364 | }; | |
5c8b718c | 365 | |
576f1b4b HW |
366 | if (event >= CMDQ_MAX_EVENT) |
367 | return -EINVAL; | |
368 | ||
5c8b718c | 369 | return cmdq_pkt_append_command(pkt, inst); |
576f1b4b HW |
370 | } |
371 | EXPORT_SYMBOL(cmdq_pkt_clear_event); | |
372 | ||
7de796ca DYH |
373 | int cmdq_pkt_set_event(struct cmdq_pkt *pkt, u16 event) |
374 | { | |
34771841 ADR |
375 | struct cmdq_instruction inst = { |
376 | .op = CMDQ_CODE_WFE, | |
377 | .value = CMDQ_WFE_UPDATE | CMDQ_WFE_UPDATE_VALUE, | |
378 | .event = event | |
379 | }; | |
7de796ca DYH |
380 | |
381 | if (event >= CMDQ_MAX_EVENT) | |
382 | return -EINVAL; | |
383 | ||
7de796ca DYH |
384 | return cmdq_pkt_append_command(pkt, inst); |
385 | } | |
386 | EXPORT_SYMBOL(cmdq_pkt_set_event); | |
387 | ||
b2ff2356 BH |
388 | int cmdq_pkt_poll(struct cmdq_pkt *pkt, u8 subsys, |
389 | u16 offset, u32 value) | |
390 | { | |
34771841 ADR |
391 | struct cmdq_instruction inst = { |
392 | .op = CMDQ_CODE_POLL, | |
393 | .value = value, | |
394 | .offset = offset, | |
395 | .subsys = subsys | |
396 | }; | |
397 | return cmdq_pkt_append_command(pkt, inst); | |
b2ff2356 BH |
398 | } |
399 | EXPORT_SYMBOL(cmdq_pkt_poll); | |
400 | ||
401 | int cmdq_pkt_poll_mask(struct cmdq_pkt *pkt, u8 subsys, | |
402 | u16 offset, u32 value, u32 mask) | |
403 | { | |
b2ff2356 BH |
404 | int err; |
405 | ||
4b334721 | 406 | err = cmdq_pkt_mask(pkt, mask); |
b2ff2356 BH |
407 | if (err < 0) |
408 | return err; | |
409 | ||
410 | offset = offset | CMDQ_POLL_ENABLE_MASK; | |
34771841 | 411 | return cmdq_pkt_poll(pkt, subsys, offset, value); |
b2ff2356 BH |
412 | } |
413 | EXPORT_SYMBOL(cmdq_pkt_poll_mask); | |
414 | ||
400e2fa8 JJL |
415 | int cmdq_pkt_poll_addr(struct cmdq_pkt *pkt, dma_addr_t addr, u32 value, u32 mask) |
416 | { | |
417 | struct cmdq_instruction inst = { {0} }; | |
418 | u8 use_mask = 0; | |
419 | int ret; | |
420 | ||
421 | /* | |
422 | * Append an MASK instruction to set the mask for following POLL instruction | |
423 | * which enables use_mask bit. | |
424 | */ | |
425 | if (mask != GENMASK(31, 0)) { | |
4b334721 | 426 | ret = cmdq_pkt_mask(pkt, mask); |
400e2fa8 JJL |
427 | if (ret < 0) |
428 | return ret; | |
429 | use_mask = CMDQ_POLL_ENABLE_MASK; | |
430 | } | |
431 | ||
432 | /* | |
433 | * POLL is an legacy operation in GCE and it does not support SPR and CMDQ_CODE_LOGIC, | |
434 | * so it can not use cmdq_pkt_assign to keep polling register address to SPR. | |
435 | * If user wants to poll a register address which doesn't have a subsys id, | |
436 | * user needs to use GPR and CMDQ_CODE_MASK to move polling register address to GPR. | |
437 | */ | |
438 | inst.op = CMDQ_CODE_MASK; | |
439 | inst.dst_t = CMDQ_REG_TYPE; | |
440 | inst.sop = CMDQ_POLL_ADDR_GPR; | |
441 | inst.value = addr; | |
442 | ret = cmdq_pkt_append_command(pkt, inst); | |
443 | if (ret < 0) | |
444 | return ret; | |
445 | ||
446 | /* Append POLL instruction to poll the register address assign to GPR previously. */ | |
447 | inst.op = CMDQ_CODE_POLL; | |
448 | inst.dst_t = CMDQ_REG_TYPE; | |
449 | inst.sop = CMDQ_POLL_ADDR_GPR; | |
450 | inst.offset = use_mask; | |
451 | inst.value = value; | |
452 | ret = cmdq_pkt_append_command(pkt, inst); | |
453 | if (ret < 0) | |
454 | return ret; | |
455 | ||
456 | return 0; | |
457 | } | |
458 | EXPORT_SYMBOL(cmdq_pkt_poll_addr); | |
459 | ||
58de63dd JJL |
460 | int cmdq_pkt_logic_command(struct cmdq_pkt *pkt, u16 result_reg_idx, |
461 | struct cmdq_operand *left_operand, | |
462 | enum cmdq_logic_op s_op, | |
463 | struct cmdq_operand *right_operand) | |
464 | { | |
34771841 | 465 | struct cmdq_instruction inst; |
58de63dd JJL |
466 | |
467 | if (!left_operand || !right_operand || s_op >= CMDQ_LOGIC_MAX) | |
468 | return -EINVAL; | |
469 | ||
34771841 | 470 | inst.value = 0; |
58de63dd JJL |
471 | inst.op = CMDQ_CODE_LOGIC; |
472 | inst.dst_t = CMDQ_REG_TYPE; | |
473 | inst.src_t = cmdq_operand_get_type(left_operand); | |
474 | inst.arg_c_t = cmdq_operand_get_type(right_operand); | |
475 | inst.sop = s_op; | |
476 | inst.reg_dst = result_reg_idx; | |
477 | inst.src_reg = cmdq_operand_get_idx_value(left_operand); | |
478 | inst.arg_c = cmdq_operand_get_idx_value(right_operand); | |
479 | ||
480 | return cmdq_pkt_append_command(pkt, inst); | |
481 | } | |
482 | EXPORT_SYMBOL(cmdq_pkt_logic_command); | |
483 | ||
613c2e2c DYH |
484 | int cmdq_pkt_assign(struct cmdq_pkt *pkt, u16 reg_idx, u32 value) |
485 | { | |
34771841 ADR |
486 | struct cmdq_instruction inst = { |
487 | .op = CMDQ_CODE_LOGIC, | |
488 | .dst_t = CMDQ_REG_TYPE, | |
489 | .reg_dst = reg_idx, | |
490 | .value = value | |
491 | }; | |
613c2e2c DYH |
492 | return cmdq_pkt_append_command(pkt, inst); |
493 | } | |
494 | EXPORT_SYMBOL(cmdq_pkt_assign); | |
495 | ||
7218be3b | 496 | int cmdq_pkt_jump_abs(struct cmdq_pkt *pkt, dma_addr_t addr, u8 shift_pa) |
946f1792 | 497 | { |
34771841 ADR |
498 | struct cmdq_instruction inst = { |
499 | .op = CMDQ_CODE_JUMP, | |
500 | .offset = CMDQ_JUMP_ABSOLUTE, | |
501 | .value = addr >> shift_pa | |
502 | }; | |
946f1792 DYH |
503 | return cmdq_pkt_append_command(pkt, inst); |
504 | } | |
7218be3b | 505 | EXPORT_SYMBOL(cmdq_pkt_jump_abs); |
946f1792 | 506 | |
698cdcb1 CKH |
507 | int cmdq_pkt_jump_rel(struct cmdq_pkt *pkt, s32 offset, u8 shift_pa) |
508 | { | |
34771841 ADR |
509 | struct cmdq_instruction inst = { |
510 | .op = CMDQ_CODE_JUMP, | |
511 | .value = (u32)offset >> shift_pa | |
512 | }; | |
698cdcb1 CKH |
513 | return cmdq_pkt_append_command(pkt, inst); |
514 | } | |
515 | EXPORT_SYMBOL(cmdq_pkt_jump_rel); | |
516 | ||
3d86ced9 CKH |
517 | int cmdq_pkt_eoc(struct cmdq_pkt *pkt) |
518 | { | |
34771841 ADR |
519 | struct cmdq_instruction inst = { |
520 | .op = CMDQ_CODE_EOC, | |
521 | .value = CMDQ_EOC_IRQ_EN | |
522 | }; | |
3d86ced9 CKH |
523 | return cmdq_pkt_append_command(pkt, inst); |
524 | } | |
525 | EXPORT_SYMBOL(cmdq_pkt_eoc); | |
526 | ||
a862a3f7 | 527 | MODULE_DESCRIPTION("MediaTek Command Queue (CMDQ) driver"); |
576f1b4b | 528 | MODULE_LICENSE("GPL v2"); |