1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16#include <linux/delay.h>
17#include <linux/device.h>
18#include <linux/dma-mapping.h>
19#include <linux/interrupt.h>
20#include <linux/iopoll.h>
21#include <linux/kernel.h>
22#include <linux/qcom_scm.h>
23#include <linux/slab.h>
24
25#include "core.h"
26#include "hfi_cmds.h"
27#include "hfi_msgs.h"
28#include "hfi_venus.h"
29#include "hfi_venus_io.h"
30
31#define HFI_MASK_QHDR_TX_TYPE 0xff000000
32#define HFI_MASK_QHDR_RX_TYPE 0x00ff0000
33#define HFI_MASK_QHDR_PRI_TYPE 0x0000ff00
34#define HFI_MASK_QHDR_ID_TYPE 0x000000ff
35
36#define HFI_HOST_TO_CTRL_CMD_Q 0
37#define HFI_CTRL_TO_HOST_MSG_Q 1
38#define HFI_CTRL_TO_HOST_DBG_Q 2
39#define HFI_MASK_QHDR_STATUS 0x000000ff
40
41#define IFACEQ_NUM 3
42#define IFACEQ_CMD_IDX 0
43#define IFACEQ_MSG_IDX 1
44#define IFACEQ_DBG_IDX 2
45#define IFACEQ_MAX_BUF_COUNT 50
46#define IFACEQ_MAX_PARALLEL_CLNTS 16
47#define IFACEQ_DFLT_QHDR 0x01010000
48
49#define POLL_INTERVAL_US 50
50
51#define IFACEQ_MAX_PKT_SIZE 1024
52#define IFACEQ_MED_PKT_SIZE 768
53#define IFACEQ_MIN_PKT_SIZE 8
54#define IFACEQ_VAR_SMALL_PKT_SIZE 100
55#define IFACEQ_VAR_LARGE_PKT_SIZE 512
56#define IFACEQ_VAR_HUGE_PKT_SIZE (1024 * 12)
57
58enum tzbsp_video_state {
59 TZBSP_VIDEO_STATE_SUSPEND = 0,
60 TZBSP_VIDEO_STATE_RESUME
61};
62
63struct hfi_queue_table_header {
64 u32 version;
65 u32 size;
66 u32 qhdr0_offset;
67 u32 qhdr_size;
68 u32 num_q;
69 u32 num_active_q;
70};
71
72struct hfi_queue_header {
73 u32 status;
74 u32 start_addr;
75 u32 type;
76 u32 q_size;
77 u32 pkt_size;
78 u32 pkt_drop_cnt;
79 u32 rx_wm;
80 u32 tx_wm;
81 u32 rx_req;
82 u32 tx_req;
83 u32 rx_irq_status;
84 u32 tx_irq_status;
85 u32 read_idx;
86 u32 write_idx;
87};
88
89#define IFACEQ_TABLE_SIZE \
90 (sizeof(struct hfi_queue_table_header) + \
91 sizeof(struct hfi_queue_header) * IFACEQ_NUM)
92
93#define IFACEQ_QUEUE_SIZE (IFACEQ_MAX_PKT_SIZE * \
94 IFACEQ_MAX_BUF_COUNT * IFACEQ_MAX_PARALLEL_CLNTS)
95
96#define IFACEQ_GET_QHDR_START_ADDR(ptr, i) \
97 (void *)(((ptr) + sizeof(struct hfi_queue_table_header)) + \
98 ((i) * sizeof(struct hfi_queue_header)))
99
100#define QDSS_SIZE SZ_4K
101#define SFR_SIZE SZ_4K
102#define QUEUE_SIZE \
103 (IFACEQ_TABLE_SIZE + (IFACEQ_QUEUE_SIZE * IFACEQ_NUM))
104
105#define ALIGNED_QDSS_SIZE ALIGN(QDSS_SIZE, SZ_4K)
106#define ALIGNED_SFR_SIZE ALIGN(SFR_SIZE, SZ_4K)
107#define ALIGNED_QUEUE_SIZE ALIGN(QUEUE_SIZE, SZ_4K)
108#define SHARED_QSIZE ALIGN(ALIGNED_SFR_SIZE + ALIGNED_QUEUE_SIZE + \
109 ALIGNED_QDSS_SIZE, SZ_1M)
110
111struct mem_desc {
112 dma_addr_t da;
113 void *kva;
114 u32 size;
115 unsigned long attrs;
116};
117
118struct iface_queue {
119 struct hfi_queue_header *qhdr;
120 struct mem_desc qmem;
121};
122
123enum venus_state {
124 VENUS_STATE_DEINIT = 1,
125 VENUS_STATE_INIT,
126};
127
128struct venus_hfi_device {
129 struct venus_core *core;
130 u32 irq_status;
131 u32 last_packet_type;
132 bool power_enabled;
133 bool suspended;
134 enum venus_state state;
135
136 struct mutex lock;
137 struct completion pwr_collapse_prep;
138 struct completion release_resource;
139 struct mem_desc ifaceq_table;
140 struct mem_desc sfr;
141 struct iface_queue queues[IFACEQ_NUM];
142 u8 pkt_buf[IFACEQ_VAR_HUGE_PKT_SIZE];
143 u8 dbg_buf[IFACEQ_VAR_HUGE_PKT_SIZE];
144};
145
146static bool venus_pkt_debug;
147static int venus_fw_debug = HFI_DEBUG_MSG_ERROR | HFI_DEBUG_MSG_FATAL;
148static bool venus_sys_idle_indicator;
149static bool venus_fw_low_power_mode = true;
150static int venus_hw_rsp_timeout = 1000;
151static bool venus_fw_coverage;
152
153static void venus_set_state(struct venus_hfi_device *hdev,
154 enum venus_state state)
155{
156 mutex_lock(&hdev->lock);
157 hdev->state = state;
158 mutex_unlock(&hdev->lock);
159}
160
161static bool venus_is_valid_state(struct venus_hfi_device *hdev)
162{
163 return hdev->state != VENUS_STATE_DEINIT;
164}
165
166static void venus_dump_packet(struct venus_hfi_device *hdev, const void *packet)
167{
168 size_t pkt_size = *(u32 *)packet;
169
170 if (!venus_pkt_debug)
171 return;
172
173 print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 16, 1, packet,
174 pkt_size, true);
175}
176
177static int venus_write_queue(struct venus_hfi_device *hdev,
178 struct iface_queue *queue,
179 void *packet, u32 *rx_req)
180{
181 struct hfi_queue_header *qhdr;
182 u32 dwords, new_wr_idx;
183 u32 empty_space, rd_idx, wr_idx, qsize;
184 u32 *wr_ptr;
185
186 if (!queue->qmem.kva)
187 return -EINVAL;
188
189 qhdr = queue->qhdr;
190 if (!qhdr)
191 return -EINVAL;
192
193 venus_dump_packet(hdev, packet);
194
195 dwords = (*(u32 *)packet) >> 2;
196 if (!dwords)
197 return -EINVAL;
198
199 rd_idx = qhdr->read_idx;
200 wr_idx = qhdr->write_idx;
201 qsize = qhdr->q_size;
202
203 rmb();
204
205 if (wr_idx >= rd_idx)
206 empty_space = qsize - (wr_idx - rd_idx);
207 else
208 empty_space = rd_idx - wr_idx;
209
210 if (empty_space <= dwords) {
211 qhdr->tx_req = 1;
212
213 wmb();
214 return -ENOSPC;
215 }
216
217 qhdr->tx_req = 0;
218
219 wmb();
220
221 new_wr_idx = wr_idx + dwords;
222 wr_ptr = (u32 *)(queue->qmem.kva + (wr_idx << 2));
223 if (new_wr_idx < qsize) {
224 memcpy(wr_ptr, packet, dwords << 2);
225 } else {
226 size_t len;
227
228 new_wr_idx -= qsize;
229 len = (dwords - new_wr_idx) << 2;
230 memcpy(wr_ptr, packet, len);
231 memcpy(queue->qmem.kva, packet + len, new_wr_idx << 2);
232 }
233
234
235 wmb();
236
237 qhdr->write_idx = new_wr_idx;
238 *rx_req = qhdr->rx_req ? 1 : 0;
239
240
241 mb();
242
243 return 0;
244}
245
246static int venus_read_queue(struct venus_hfi_device *hdev,
247 struct iface_queue *queue, void *pkt, u32 *tx_req)
248{
249 struct hfi_queue_header *qhdr;
250 u32 dwords, new_rd_idx;
251 u32 rd_idx, wr_idx, type, qsize;
252 u32 *rd_ptr;
253 u32 recv_request = 0;
254 int ret = 0;
255
256 if (!queue->qmem.kva)
257 return -EINVAL;
258
259 qhdr = queue->qhdr;
260 if (!qhdr)
261 return -EINVAL;
262
263 type = qhdr->type;
264 rd_idx = qhdr->read_idx;
265 wr_idx = qhdr->write_idx;
266 qsize = qhdr->q_size;
267
268
269 rmb();
270
271
272
273
274
275
276
277
278 if (type & HFI_CTRL_TO_HOST_MSG_Q)
279 recv_request = 1;
280
281 if (rd_idx == wr_idx) {
282 qhdr->rx_req = recv_request;
283 *tx_req = 0;
284
285 wmb();
286 return -ENODATA;
287 }
288
289 rd_ptr = (u32 *)(queue->qmem.kva + (rd_idx << 2));
290 dwords = *rd_ptr >> 2;
291 if (!dwords)
292 return -EINVAL;
293
294 new_rd_idx = rd_idx + dwords;
295 if (((dwords << 2) <= IFACEQ_VAR_HUGE_PKT_SIZE) && rd_idx <= qsize) {
296 if (new_rd_idx < qsize) {
297 memcpy(pkt, rd_ptr, dwords << 2);
298 } else {
299 size_t len;
300
301 new_rd_idx -= qsize;
302 len = (dwords - new_rd_idx) << 2;
303 memcpy(pkt, rd_ptr, len);
304 memcpy(pkt + len, queue->qmem.kva, new_rd_idx << 2);
305 }
306 } else {
307
308 new_rd_idx = qhdr->write_idx;
309 ret = -EBADMSG;
310 }
311
312
313 rmb();
314
315 qhdr->read_idx = new_rd_idx;
316
317 wmb();
318
319 rd_idx = qhdr->read_idx;
320 wr_idx = qhdr->write_idx;
321
322 rmb();
323
324 if (rd_idx != wr_idx)
325 qhdr->rx_req = 0;
326 else
327 qhdr->rx_req = recv_request;
328
329 *tx_req = qhdr->tx_req ? 1 : 0;
330
331
332 mb();
333
334 venus_dump_packet(hdev, pkt);
335
336 return ret;
337}
338
339static int venus_alloc(struct venus_hfi_device *hdev, struct mem_desc *desc,
340 u32 size)
341{
342 struct device *dev = hdev->core->dev;
343
344 desc->attrs = DMA_ATTR_WRITE_COMBINE;
345 desc->size = ALIGN(size, SZ_4K);
346
347 desc->kva = dma_alloc_attrs(dev, size, &desc->da, GFP_KERNEL,
348 desc->attrs);
349 if (!desc->kva)
350 return -ENOMEM;
351
352 return 0;
353}
354
355static void venus_free(struct venus_hfi_device *hdev, struct mem_desc *mem)
356{
357 struct device *dev = hdev->core->dev;
358
359 dma_free_attrs(dev, mem->size, mem->kva, mem->da, mem->attrs);
360}
361
362static void venus_writel(struct venus_hfi_device *hdev, u32 reg, u32 value)
363{
364 writel(value, hdev->core->base + reg);
365}
366
367static u32 venus_readl(struct venus_hfi_device *hdev, u32 reg)
368{
369 return readl(hdev->core->base + reg);
370}
371
372static void venus_set_registers(struct venus_hfi_device *hdev)
373{
374 const struct venus_resources *res = hdev->core->res;
375 const struct reg_val *tbl = res->reg_tbl;
376 unsigned int count = res->reg_tbl_size;
377 unsigned int i;
378
379 for (i = 0; i < count; i++)
380 venus_writel(hdev, tbl[i].reg, tbl[i].value);
381}
382
383static void venus_soft_int(struct venus_hfi_device *hdev)
384{
385 venus_writel(hdev, CPU_IC_SOFTINT, BIT(CPU_IC_SOFTINT_H2A_SHIFT));
386}
387
388static int venus_iface_cmdq_write_nolock(struct venus_hfi_device *hdev,
389 void *pkt)
390{
391 struct device *dev = hdev->core->dev;
392 struct hfi_pkt_hdr *cmd_packet;
393 struct iface_queue *queue;
394 u32 rx_req;
395 int ret;
396
397 if (!venus_is_valid_state(hdev))
398 return -EINVAL;
399
400 cmd_packet = (struct hfi_pkt_hdr *)pkt;
401 hdev->last_packet_type = cmd_packet->pkt_type;
402
403 queue = &hdev->queues[IFACEQ_CMD_IDX];
404
405 ret = venus_write_queue(hdev, queue, pkt, &rx_req);
406 if (ret) {
407 dev_err(dev, "write to iface cmd queue failed (%d)\n", ret);
408 return ret;
409 }
410
411 if (rx_req)
412 venus_soft_int(hdev);
413
414 return 0;
415}
416
417static int venus_iface_cmdq_write(struct venus_hfi_device *hdev, void *pkt)
418{
419 int ret;
420
421 mutex_lock(&hdev->lock);
422 ret = venus_iface_cmdq_write_nolock(hdev, pkt);
423 mutex_unlock(&hdev->lock);
424
425 return ret;
426}
427
428static int venus_hfi_core_set_resource(struct venus_core *core, u32 id,
429 u32 size, u32 addr, void *cookie)
430{
431 struct venus_hfi_device *hdev = to_hfi_priv(core);
432 struct hfi_sys_set_resource_pkt *pkt;
433 u8 packet[IFACEQ_VAR_SMALL_PKT_SIZE];
434 int ret;
435
436 if (id == VIDC_RESOURCE_NONE)
437 return 0;
438
439 pkt = (struct hfi_sys_set_resource_pkt *)packet;
440
441 ret = pkt_sys_set_resource(pkt, id, size, addr, cookie);
442 if (ret)
443 return ret;
444
445 ret = venus_iface_cmdq_write(hdev, pkt);
446 if (ret)
447 return ret;
448
449 return 0;
450}
451
452static int venus_boot_core(struct venus_hfi_device *hdev)
453{
454 struct device *dev = hdev->core->dev;
455 static const unsigned int max_tries = 100;
456 u32 ctrl_status = 0;
457 unsigned int count = 0;
458 int ret = 0;
459
460 venus_writel(hdev, VIDC_CTRL_INIT, BIT(VIDC_CTRL_INIT_CTRL_SHIFT));
461 venus_writel(hdev, WRAPPER_INTR_MASK, WRAPPER_INTR_MASK_A2HVCODEC_MASK);
462 venus_writel(hdev, CPU_CS_SCIACMDARG3, 1);
463
464 while (!ctrl_status && count < max_tries) {
465 ctrl_status = venus_readl(hdev, CPU_CS_SCIACMDARG0);
466 if ((ctrl_status & CPU_CS_SCIACMDARG0_ERROR_STATUS_MASK) == 4) {
467 dev_err(dev, "invalid setting for UC_REGION\n");
468 ret = -EINVAL;
469 break;
470 }
471
472 usleep_range(500, 1000);
473 count++;
474 }
475
476 if (count >= max_tries)
477 ret = -ETIMEDOUT;
478
479 return ret;
480}
481
482static u32 venus_hwversion(struct venus_hfi_device *hdev)
483{
484 struct device *dev = hdev->core->dev;
485 u32 ver = venus_readl(hdev, WRAPPER_HW_VERSION);
486 u32 major, minor, step;
487
488 major = ver & WRAPPER_HW_VERSION_MAJOR_VERSION_MASK;
489 major = major >> WRAPPER_HW_VERSION_MAJOR_VERSION_SHIFT;
490 minor = ver & WRAPPER_HW_VERSION_MINOR_VERSION_MASK;
491 minor = minor >> WRAPPER_HW_VERSION_MINOR_VERSION_SHIFT;
492 step = ver & WRAPPER_HW_VERSION_STEP_VERSION_MASK;
493
494 dev_dbg(dev, "venus hw version %x.%x.%x\n", major, minor, step);
495
496 return major;
497}
498
499static int venus_run(struct venus_hfi_device *hdev)
500{
501 struct device *dev = hdev->core->dev;
502 int ret;
503
504
505
506
507
508 venus_set_registers(hdev);
509
510 venus_writel(hdev, UC_REGION_ADDR, hdev->ifaceq_table.da);
511 venus_writel(hdev, UC_REGION_SIZE, SHARED_QSIZE);
512 venus_writel(hdev, CPU_CS_SCIACMDARG2, hdev->ifaceq_table.da);
513 venus_writel(hdev, CPU_CS_SCIACMDARG1, 0x01);
514 if (hdev->sfr.da)
515 venus_writel(hdev, SFR_ADDR, hdev->sfr.da);
516
517 ret = venus_boot_core(hdev);
518 if (ret) {
519 dev_err(dev, "failed to reset venus core\n");
520 return ret;
521 }
522
523 venus_hwversion(hdev);
524
525 return 0;
526}
527
528static int venus_halt_axi(struct venus_hfi_device *hdev)
529{
530 void __iomem *base = hdev->core->base;
531 struct device *dev = hdev->core->dev;
532 u32 val;
533 int ret;
534
535
536 val = venus_readl(hdev, VBIF_AXI_HALT_CTRL0);
537 val |= VBIF_AXI_HALT_CTRL0_HALT_REQ;
538 venus_writel(hdev, VBIF_AXI_HALT_CTRL0, val);
539
540
541 ret = readl_poll_timeout(base + VBIF_AXI_HALT_CTRL1, val,
542 val & VBIF_AXI_HALT_CTRL1_HALT_ACK,
543 POLL_INTERVAL_US,
544 VBIF_AXI_HALT_ACK_TIMEOUT_US);
545 if (ret) {
546 dev_err(dev, "AXI bus port halt timeout\n");
547 return ret;
548 }
549
550 return 0;
551}
552
553static int venus_power_off(struct venus_hfi_device *hdev)
554{
555 int ret;
556
557 if (!hdev->power_enabled)
558 return 0;
559
560 ret = qcom_scm_set_remote_state(TZBSP_VIDEO_STATE_SUSPEND, 0);
561 if (ret)
562 return ret;
563
564 ret = venus_halt_axi(hdev);
565 if (ret)
566 return ret;
567
568 hdev->power_enabled = false;
569
570 return 0;
571}
572
573static int venus_power_on(struct venus_hfi_device *hdev)
574{
575 int ret;
576
577 if (hdev->power_enabled)
578 return 0;
579
580 ret = qcom_scm_set_remote_state(TZBSP_VIDEO_STATE_RESUME, 0);
581 if (ret)
582 goto err;
583
584 ret = venus_run(hdev);
585 if (ret)
586 goto err_suspend;
587
588 hdev->power_enabled = true;
589
590 return 0;
591
592err_suspend:
593 qcom_scm_set_remote_state(TZBSP_VIDEO_STATE_SUSPEND, 0);
594err:
595 hdev->power_enabled = false;
596 return ret;
597}
598
599static int venus_iface_msgq_read_nolock(struct venus_hfi_device *hdev,
600 void *pkt)
601{
602 struct iface_queue *queue;
603 u32 tx_req;
604 int ret;
605
606 if (!venus_is_valid_state(hdev))
607 return -EINVAL;
608
609 queue = &hdev->queues[IFACEQ_MSG_IDX];
610
611 ret = venus_read_queue(hdev, queue, pkt, &tx_req);
612 if (ret)
613 return ret;
614
615 if (tx_req)
616 venus_soft_int(hdev);
617
618 return 0;
619}
620
621static int venus_iface_msgq_read(struct venus_hfi_device *hdev, void *pkt)
622{
623 int ret;
624
625 mutex_lock(&hdev->lock);
626 ret = venus_iface_msgq_read_nolock(hdev, pkt);
627 mutex_unlock(&hdev->lock);
628
629 return ret;
630}
631
632static int venus_iface_dbgq_read_nolock(struct venus_hfi_device *hdev,
633 void *pkt)
634{
635 struct iface_queue *queue;
636 u32 tx_req;
637 int ret;
638
639 ret = venus_is_valid_state(hdev);
640 if (!ret)
641 return -EINVAL;
642
643 queue = &hdev->queues[IFACEQ_DBG_IDX];
644
645 ret = venus_read_queue(hdev, queue, pkt, &tx_req);
646 if (ret)
647 return ret;
648
649 if (tx_req)
650 venus_soft_int(hdev);
651
652 return 0;
653}
654
655static int venus_iface_dbgq_read(struct venus_hfi_device *hdev, void *pkt)
656{
657 int ret;
658
659 if (!pkt)
660 return -EINVAL;
661
662 mutex_lock(&hdev->lock);
663 ret = venus_iface_dbgq_read_nolock(hdev, pkt);
664 mutex_unlock(&hdev->lock);
665
666 return ret;
667}
668
669static void venus_set_qhdr_defaults(struct hfi_queue_header *qhdr)
670{
671 qhdr->status = 1;
672 qhdr->type = IFACEQ_DFLT_QHDR;
673 qhdr->q_size = IFACEQ_QUEUE_SIZE / 4;
674 qhdr->pkt_size = 0;
675 qhdr->rx_wm = 1;
676 qhdr->tx_wm = 1;
677 qhdr->rx_req = 1;
678 qhdr->tx_req = 0;
679 qhdr->rx_irq_status = 0;
680 qhdr->tx_irq_status = 0;
681 qhdr->read_idx = 0;
682 qhdr->write_idx = 0;
683}
684
685static void venus_interface_queues_release(struct venus_hfi_device *hdev)
686{
687 mutex_lock(&hdev->lock);
688
689 venus_free(hdev, &hdev->ifaceq_table);
690 venus_free(hdev, &hdev->sfr);
691
692 memset(hdev->queues, 0, sizeof(hdev->queues));
693 memset(&hdev->ifaceq_table, 0, sizeof(hdev->ifaceq_table));
694 memset(&hdev->sfr, 0, sizeof(hdev->sfr));
695
696 mutex_unlock(&hdev->lock);
697}
698
699static int venus_interface_queues_init(struct venus_hfi_device *hdev)
700{
701 struct hfi_queue_table_header *tbl_hdr;
702 struct iface_queue *queue;
703 struct hfi_sfr *sfr;
704 struct mem_desc desc = {0};
705 unsigned int offset;
706 unsigned int i;
707 int ret;
708
709 ret = venus_alloc(hdev, &desc, ALIGNED_QUEUE_SIZE);
710 if (ret)
711 return ret;
712
713 hdev->ifaceq_table.kva = desc.kva;
714 hdev->ifaceq_table.da = desc.da;
715 hdev->ifaceq_table.size = IFACEQ_TABLE_SIZE;
716 offset = hdev->ifaceq_table.size;
717
718 for (i = 0; i < IFACEQ_NUM; i++) {
719 queue = &hdev->queues[i];
720 queue->qmem.da = desc.da + offset;
721 queue->qmem.kva = desc.kva + offset;
722 queue->qmem.size = IFACEQ_QUEUE_SIZE;
723 offset += queue->qmem.size;
724 queue->qhdr =
725 IFACEQ_GET_QHDR_START_ADDR(hdev->ifaceq_table.kva, i);
726
727 venus_set_qhdr_defaults(queue->qhdr);
728
729 queue->qhdr->start_addr = queue->qmem.da;
730
731 if (i == IFACEQ_CMD_IDX)
732 queue->qhdr->type |= HFI_HOST_TO_CTRL_CMD_Q;
733 else if (i == IFACEQ_MSG_IDX)
734 queue->qhdr->type |= HFI_CTRL_TO_HOST_MSG_Q;
735 else if (i == IFACEQ_DBG_IDX)
736 queue->qhdr->type |= HFI_CTRL_TO_HOST_DBG_Q;
737 }
738
739 tbl_hdr = hdev->ifaceq_table.kva;
740 tbl_hdr->version = 0;
741 tbl_hdr->size = IFACEQ_TABLE_SIZE;
742 tbl_hdr->qhdr0_offset = sizeof(struct hfi_queue_table_header);
743 tbl_hdr->qhdr_size = sizeof(struct hfi_queue_header);
744 tbl_hdr->num_q = IFACEQ_NUM;
745 tbl_hdr->num_active_q = IFACEQ_NUM;
746
747
748
749
750
751 queue = &hdev->queues[IFACEQ_DBG_IDX];
752 queue->qhdr->rx_req = 0;
753
754 ret = venus_alloc(hdev, &desc, ALIGNED_SFR_SIZE);
755 if (ret) {
756 hdev->sfr.da = 0;
757 } else {
758 hdev->sfr.da = desc.da;
759 hdev->sfr.kva = desc.kva;
760 hdev->sfr.size = ALIGNED_SFR_SIZE;
761 sfr = hdev->sfr.kva;
762 sfr->buf_size = ALIGNED_SFR_SIZE;
763 }
764
765
766 wmb();
767
768 return 0;
769}
770
771static int venus_sys_set_debug(struct venus_hfi_device *hdev, u32 debug)
772{
773 struct hfi_sys_set_property_pkt *pkt;
774 u8 packet[IFACEQ_VAR_SMALL_PKT_SIZE];
775 int ret;
776
777 pkt = (struct hfi_sys_set_property_pkt *)packet;
778
779 pkt_sys_debug_config(pkt, HFI_DEBUG_MODE_QUEUE, debug);
780
781 ret = venus_iface_cmdq_write(hdev, pkt);
782 if (ret)
783 return ret;
784
785 return 0;
786}
787
788static int venus_sys_set_coverage(struct venus_hfi_device *hdev, u32 mode)
789{
790 struct hfi_sys_set_property_pkt *pkt;
791 u8 packet[IFACEQ_VAR_SMALL_PKT_SIZE];
792 int ret;
793
794 pkt = (struct hfi_sys_set_property_pkt *)packet;
795
796 pkt_sys_coverage_config(pkt, mode);
797
798 ret = venus_iface_cmdq_write(hdev, pkt);
799 if (ret)
800 return ret;
801
802 return 0;
803}
804
805static int venus_sys_set_idle_message(struct venus_hfi_device *hdev,
806 bool enable)
807{
808 struct hfi_sys_set_property_pkt *pkt;
809 u8 packet[IFACEQ_VAR_SMALL_PKT_SIZE];
810 int ret;
811
812 if (!enable)
813 return 0;
814
815 pkt = (struct hfi_sys_set_property_pkt *)packet;
816
817 pkt_sys_idle_indicator(pkt, enable);
818
819 ret = venus_iface_cmdq_write(hdev, pkt);
820 if (ret)
821 return ret;
822
823 return 0;
824}
825
826static int venus_sys_set_power_control(struct venus_hfi_device *hdev,
827 bool enable)
828{
829 struct hfi_sys_set_property_pkt *pkt;
830 u8 packet[IFACEQ_VAR_SMALL_PKT_SIZE];
831 int ret;
832
833 pkt = (struct hfi_sys_set_property_pkt *)packet;
834
835 pkt_sys_power_control(pkt, enable);
836
837 ret = venus_iface_cmdq_write(hdev, pkt);
838 if (ret)
839 return ret;
840
841 return 0;
842}
843
844static int venus_get_queue_size(struct venus_hfi_device *hdev,
845 unsigned int index)
846{
847 struct hfi_queue_header *qhdr;
848
849 if (index >= IFACEQ_NUM)
850 return -EINVAL;
851
852 qhdr = hdev->queues[index].qhdr;
853 if (!qhdr)
854 return -EINVAL;
855
856 return abs(qhdr->read_idx - qhdr->write_idx);
857}
858
859static int venus_sys_set_default_properties(struct venus_hfi_device *hdev)
860{
861 struct device *dev = hdev->core->dev;
862 int ret;
863
864 ret = venus_sys_set_debug(hdev, venus_fw_debug);
865 if (ret)
866 dev_warn(dev, "setting fw debug msg ON failed (%d)\n", ret);
867
868 ret = venus_sys_set_idle_message(hdev, venus_sys_idle_indicator);
869 if (ret)
870 dev_warn(dev, "setting idle response ON failed (%d)\n", ret);
871
872 ret = venus_sys_set_power_control(hdev, venus_fw_low_power_mode);
873 if (ret)
874 dev_warn(dev, "setting hw power collapse ON failed (%d)\n",
875 ret);
876
877 return ret;
878}
879
880static int venus_session_cmd(struct venus_inst *inst, u32 pkt_type)
881{
882 struct venus_hfi_device *hdev = to_hfi_priv(inst->core);
883 struct hfi_session_pkt pkt;
884
885 pkt_session_cmd(&pkt, pkt_type, inst);
886
887 return venus_iface_cmdq_write(hdev, &pkt);
888}
889
890static void venus_flush_debug_queue(struct venus_hfi_device *hdev)
891{
892 struct device *dev = hdev->core->dev;
893 void *packet = hdev->dbg_buf;
894
895 while (!venus_iface_dbgq_read(hdev, packet)) {
896 struct hfi_msg_sys_coverage_pkt *pkt = packet;
897
898 if (pkt->hdr.pkt_type != HFI_MSG_SYS_COV) {
899 struct hfi_msg_sys_debug_pkt *pkt = packet;
900
901 dev_dbg(dev, "%s", pkt->msg_data);
902 }
903 }
904}
905
906static int venus_prepare_power_collapse(struct venus_hfi_device *hdev,
907 bool wait)
908{
909 unsigned long timeout = msecs_to_jiffies(venus_hw_rsp_timeout);
910 struct hfi_sys_pc_prep_pkt pkt;
911 int ret;
912
913 init_completion(&hdev->pwr_collapse_prep);
914
915 pkt_sys_pc_prep(&pkt);
916
917 ret = venus_iface_cmdq_write(hdev, &pkt);
918 if (ret)
919 return ret;
920
921 if (!wait)
922 return 0;
923
924 ret = wait_for_completion_timeout(&hdev->pwr_collapse_prep, timeout);
925 if (!ret) {
926 venus_flush_debug_queue(hdev);
927 return -ETIMEDOUT;
928 }
929
930 return 0;
931}
932
933static int venus_are_queues_empty(struct venus_hfi_device *hdev)
934{
935 int ret1, ret2;
936
937 ret1 = venus_get_queue_size(hdev, IFACEQ_MSG_IDX);
938 if (ret1 < 0)
939 return ret1;
940
941 ret2 = venus_get_queue_size(hdev, IFACEQ_CMD_IDX);
942 if (ret2 < 0)
943 return ret2;
944
945 if (!ret1 && !ret2)
946 return 1;
947
948 return 0;
949}
950
951static void venus_sfr_print(struct venus_hfi_device *hdev)
952{
953 struct device *dev = hdev->core->dev;
954 struct hfi_sfr *sfr = hdev->sfr.kva;
955 void *p;
956
957 if (!sfr)
958 return;
959
960 p = memchr(sfr->data, '\0', sfr->buf_size);
961
962
963
964
965 if (!p)
966 sfr->data[sfr->buf_size - 1] = '\0';
967
968 dev_err_ratelimited(dev, "SFR message from FW: %s\n", sfr->data);
969}
970
971static void venus_process_msg_sys_error(struct venus_hfi_device *hdev,
972 void *packet)
973{
974 struct hfi_msg_event_notify_pkt *event_pkt = packet;
975
976 if (event_pkt->event_id != HFI_EVENT_SYS_ERROR)
977 return;
978
979 venus_set_state(hdev, VENUS_STATE_DEINIT);
980
981
982
983
984
985
986
987 venus_halt_axi(hdev);
988 venus_sfr_print(hdev);
989}
990
991static irqreturn_t venus_isr_thread(struct venus_core *core)
992{
993 struct venus_hfi_device *hdev = to_hfi_priv(core);
994 const struct venus_resources *res;
995 void *pkt;
996 u32 msg_ret;
997
998 if (!hdev)
999 return IRQ_NONE;
1000
1001 res = hdev->core->res;
1002 pkt = hdev->pkt_buf;
1003
1004 if (hdev->irq_status & WRAPPER_INTR_STATUS_A2HWD_MASK) {
1005 venus_sfr_print(hdev);
1006 hfi_process_watchdog_timeout(core);
1007 }
1008
1009 while (!venus_iface_msgq_read(hdev, pkt)) {
1010 msg_ret = hfi_process_msg_packet(core, pkt);
1011 switch (msg_ret) {
1012 case HFI_MSG_EVENT_NOTIFY:
1013 venus_process_msg_sys_error(hdev, pkt);
1014 break;
1015 case HFI_MSG_SYS_INIT:
1016 venus_hfi_core_set_resource(core, res->vmem_id,
1017 res->vmem_size,
1018 res->vmem_addr,
1019 hdev);
1020 break;
1021 case HFI_MSG_SYS_RELEASE_RESOURCE:
1022 complete(&hdev->release_resource);
1023 break;
1024 case HFI_MSG_SYS_PC_PREP:
1025 complete(&hdev->pwr_collapse_prep);
1026 break;
1027 default:
1028 break;
1029 }
1030 }
1031
1032 venus_flush_debug_queue(hdev);
1033
1034 return IRQ_HANDLED;
1035}
1036
1037static irqreturn_t venus_isr(struct venus_core *core)
1038{
1039 struct venus_hfi_device *hdev = to_hfi_priv(core);
1040 u32 status;
1041
1042 if (!hdev)
1043 return IRQ_NONE;
1044
1045 status = venus_readl(hdev, WRAPPER_INTR_STATUS);
1046
1047 if (status & WRAPPER_INTR_STATUS_A2H_MASK ||
1048 status & WRAPPER_INTR_STATUS_A2HWD_MASK ||
1049 status & CPU_CS_SCIACMDARG0_INIT_IDLE_MSG_MASK)
1050 hdev->irq_status = status;
1051
1052 venus_writel(hdev, CPU_CS_A2HSOFTINTCLR, 1);
1053 venus_writel(hdev, WRAPPER_INTR_CLEAR, status);
1054
1055 return IRQ_WAKE_THREAD;
1056}
1057
1058static int venus_core_init(struct venus_core *core)
1059{
1060 struct venus_hfi_device *hdev = to_hfi_priv(core);
1061 struct device *dev = core->dev;
1062 struct hfi_sys_get_property_pkt version_pkt;
1063 struct hfi_sys_init_pkt pkt;
1064 int ret;
1065
1066 pkt_sys_init(&pkt, HFI_VIDEO_ARCH_OX);
1067
1068 venus_set_state(hdev, VENUS_STATE_INIT);
1069
1070 ret = venus_iface_cmdq_write(hdev, &pkt);
1071 if (ret)
1072 return ret;
1073
1074 pkt_sys_image_version(&version_pkt);
1075
1076 ret = venus_iface_cmdq_write(hdev, &version_pkt);
1077 if (ret)
1078 dev_warn(dev, "failed to send image version pkt to fw\n");
1079
1080 return 0;
1081}
1082
1083static int venus_core_deinit(struct venus_core *core)
1084{
1085 struct venus_hfi_device *hdev = to_hfi_priv(core);
1086
1087 venus_set_state(hdev, VENUS_STATE_DEINIT);
1088 hdev->suspended = true;
1089 hdev->power_enabled = false;
1090
1091 return 0;
1092}
1093
1094static int venus_core_ping(struct venus_core *core, u32 cookie)
1095{
1096 struct venus_hfi_device *hdev = to_hfi_priv(core);
1097 struct hfi_sys_ping_pkt pkt;
1098
1099 pkt_sys_ping(&pkt, cookie);
1100
1101 return venus_iface_cmdq_write(hdev, &pkt);
1102}
1103
1104static int venus_core_trigger_ssr(struct venus_core *core, u32 trigger_type)
1105{
1106 struct venus_hfi_device *hdev = to_hfi_priv(core);
1107 struct hfi_sys_test_ssr_pkt pkt;
1108 int ret;
1109
1110 ret = pkt_sys_ssr_cmd(&pkt, trigger_type);
1111 if (ret)
1112 return ret;
1113
1114 return venus_iface_cmdq_write(hdev, &pkt);
1115}
1116
1117static int venus_session_init(struct venus_inst *inst, u32 session_type,
1118 u32 codec)
1119{
1120 struct venus_hfi_device *hdev = to_hfi_priv(inst->core);
1121 struct hfi_session_init_pkt pkt;
1122 int ret;
1123
1124 ret = venus_sys_set_default_properties(hdev);
1125 if (ret)
1126 return ret;
1127
1128 ret = pkt_session_init(&pkt, inst, session_type, codec);
1129 if (ret)
1130 goto err;
1131
1132 ret = venus_iface_cmdq_write(hdev, &pkt);
1133 if (ret)
1134 goto err;
1135
1136 return 0;
1137
1138err:
1139 venus_flush_debug_queue(hdev);
1140 return ret;
1141}
1142
1143static int venus_session_end(struct venus_inst *inst)
1144{
1145 struct venus_hfi_device *hdev = to_hfi_priv(inst->core);
1146 struct device *dev = hdev->core->dev;
1147
1148 if (venus_fw_coverage) {
1149 if (venus_sys_set_coverage(hdev, venus_fw_coverage))
1150 dev_warn(dev, "fw coverage msg ON failed\n");
1151 }
1152
1153 return venus_session_cmd(inst, HFI_CMD_SYS_SESSION_END);
1154}
1155
1156static int venus_session_abort(struct venus_inst *inst)
1157{
1158 struct venus_hfi_device *hdev = to_hfi_priv(inst->core);
1159
1160 venus_flush_debug_queue(hdev);
1161
1162 return venus_session_cmd(inst, HFI_CMD_SYS_SESSION_ABORT);
1163}
1164
1165static int venus_session_flush(struct venus_inst *inst, u32 flush_mode)
1166{
1167 struct venus_hfi_device *hdev = to_hfi_priv(inst->core);
1168 struct hfi_session_flush_pkt pkt;
1169 int ret;
1170
1171 ret = pkt_session_flush(&pkt, inst, flush_mode);
1172 if (ret)
1173 return ret;
1174
1175 return venus_iface_cmdq_write(hdev, &pkt);
1176}
1177
1178static int venus_session_start(struct venus_inst *inst)
1179{
1180 return venus_session_cmd(inst, HFI_CMD_SESSION_START);
1181}
1182
1183static int venus_session_stop(struct venus_inst *inst)
1184{
1185 return venus_session_cmd(inst, HFI_CMD_SESSION_STOP);
1186}
1187
1188static int venus_session_continue(struct venus_inst *inst)
1189{
1190 return venus_session_cmd(inst, HFI_CMD_SESSION_CONTINUE);
1191}
1192
1193static int venus_session_etb(struct venus_inst *inst,
1194 struct hfi_frame_data *in_frame)
1195{
1196 struct venus_hfi_device *hdev = to_hfi_priv(inst->core);
1197 u32 session_type = inst->session_type;
1198 int ret;
1199
1200 if (session_type == VIDC_SESSION_TYPE_DEC) {
1201 struct hfi_session_empty_buffer_compressed_pkt pkt;
1202
1203 ret = pkt_session_etb_decoder(&pkt, inst, in_frame);
1204 if (ret)
1205 return ret;
1206
1207 ret = venus_iface_cmdq_write(hdev, &pkt);
1208 } else if (session_type == VIDC_SESSION_TYPE_ENC) {
1209 struct hfi_session_empty_buffer_uncompressed_plane0_pkt pkt;
1210
1211 ret = pkt_session_etb_encoder(&pkt, inst, in_frame);
1212 if (ret)
1213 return ret;
1214
1215 ret = venus_iface_cmdq_write(hdev, &pkt);
1216 } else {
1217 ret = -EINVAL;
1218 }
1219
1220 return ret;
1221}
1222
1223static int venus_session_ftb(struct venus_inst *inst,
1224 struct hfi_frame_data *out_frame)
1225{
1226 struct venus_hfi_device *hdev = to_hfi_priv(inst->core);
1227 struct hfi_session_fill_buffer_pkt pkt;
1228 int ret;
1229
1230 ret = pkt_session_ftb(&pkt, inst, out_frame);
1231 if (ret)
1232 return ret;
1233
1234 return venus_iface_cmdq_write(hdev, &pkt);
1235}
1236
1237static int venus_session_set_buffers(struct venus_inst *inst,
1238 struct hfi_buffer_desc *bd)
1239{
1240 struct venus_hfi_device *hdev = to_hfi_priv(inst->core);
1241 struct hfi_session_set_buffers_pkt *pkt;
1242 u8 packet[IFACEQ_VAR_LARGE_PKT_SIZE];
1243 int ret;
1244
1245 if (bd->buffer_type == HFI_BUFFER_INPUT)
1246 return 0;
1247
1248 pkt = (struct hfi_session_set_buffers_pkt *)packet;
1249
1250 ret = pkt_session_set_buffers(pkt, inst, bd);
1251 if (ret)
1252 return ret;
1253
1254 return venus_iface_cmdq_write(hdev, pkt);
1255}
1256
1257static int venus_session_unset_buffers(struct venus_inst *inst,
1258 struct hfi_buffer_desc *bd)
1259{
1260 struct venus_hfi_device *hdev = to_hfi_priv(inst->core);
1261 struct hfi_session_release_buffer_pkt *pkt;
1262 u8 packet[IFACEQ_VAR_LARGE_PKT_SIZE];
1263 int ret;
1264
1265 if (bd->buffer_type == HFI_BUFFER_INPUT)
1266 return 0;
1267
1268 pkt = (struct hfi_session_release_buffer_pkt *)packet;
1269
1270 ret = pkt_session_unset_buffers(pkt, inst, bd);
1271 if (ret)
1272 return ret;
1273
1274 return venus_iface_cmdq_write(hdev, pkt);
1275}
1276
1277static int venus_session_load_res(struct venus_inst *inst)
1278{
1279 return venus_session_cmd(inst, HFI_CMD_SESSION_LOAD_RESOURCES);
1280}
1281
1282static int venus_session_release_res(struct venus_inst *inst)
1283{
1284 return venus_session_cmd(inst, HFI_CMD_SESSION_RELEASE_RESOURCES);
1285}
1286
1287static int venus_session_parse_seq_hdr(struct venus_inst *inst, u32 seq_hdr,
1288 u32 seq_hdr_len)
1289{
1290 struct venus_hfi_device *hdev = to_hfi_priv(inst->core);
1291 struct hfi_session_parse_sequence_header_pkt *pkt;
1292 u8 packet[IFACEQ_VAR_SMALL_PKT_SIZE];
1293 int ret;
1294
1295 pkt = (struct hfi_session_parse_sequence_header_pkt *)packet;
1296
1297 ret = pkt_session_parse_seq_header(pkt, inst, seq_hdr, seq_hdr_len);
1298 if (ret)
1299 return ret;
1300
1301 ret = venus_iface_cmdq_write(hdev, pkt);
1302 if (ret)
1303 return ret;
1304
1305 return 0;
1306}
1307
1308static int venus_session_get_seq_hdr(struct venus_inst *inst, u32 seq_hdr,
1309 u32 seq_hdr_len)
1310{
1311 struct venus_hfi_device *hdev = to_hfi_priv(inst->core);
1312 struct hfi_session_get_sequence_header_pkt *pkt;
1313 u8 packet[IFACEQ_VAR_SMALL_PKT_SIZE];
1314 int ret;
1315
1316 pkt = (struct hfi_session_get_sequence_header_pkt *)packet;
1317
1318 ret = pkt_session_get_seq_hdr(pkt, inst, seq_hdr, seq_hdr_len);
1319 if (ret)
1320 return ret;
1321
1322 return venus_iface_cmdq_write(hdev, pkt);
1323}
1324
1325static int venus_session_set_property(struct venus_inst *inst, u32 ptype,
1326 void *pdata)
1327{
1328 struct venus_hfi_device *hdev = to_hfi_priv(inst->core);
1329 struct hfi_session_set_property_pkt *pkt;
1330 u8 packet[IFACEQ_VAR_LARGE_PKT_SIZE];
1331 int ret;
1332
1333 pkt = (struct hfi_session_set_property_pkt *)packet;
1334
1335 ret = pkt_session_set_property(pkt, inst, ptype, pdata);
1336 if (ret)
1337 return ret;
1338
1339 return venus_iface_cmdq_write(hdev, pkt);
1340}
1341
1342static int venus_session_get_property(struct venus_inst *inst, u32 ptype)
1343{
1344 struct venus_hfi_device *hdev = to_hfi_priv(inst->core);
1345 struct hfi_session_get_property_pkt pkt;
1346 int ret;
1347
1348 ret = pkt_session_get_property(&pkt, inst, ptype);
1349 if (ret)
1350 return ret;
1351
1352 return venus_iface_cmdq_write(hdev, &pkt);
1353}
1354
1355static int venus_resume(struct venus_core *core)
1356{
1357 struct venus_hfi_device *hdev = to_hfi_priv(core);
1358 int ret = 0;
1359
1360 mutex_lock(&hdev->lock);
1361
1362 if (!hdev->suspended)
1363 goto unlock;
1364
1365 ret = venus_power_on(hdev);
1366
1367unlock:
1368 if (!ret)
1369 hdev->suspended = false;
1370
1371 mutex_unlock(&hdev->lock);
1372
1373 return ret;
1374}
1375
1376static int venus_suspend_1xx(struct venus_core *core)
1377{
1378 struct venus_hfi_device *hdev = to_hfi_priv(core);
1379 struct device *dev = core->dev;
1380 u32 ctrl_status;
1381 int ret;
1382
1383 if (!hdev->power_enabled || hdev->suspended)
1384 return 0;
1385
1386 mutex_lock(&hdev->lock);
1387 ret = venus_is_valid_state(hdev);
1388 mutex_unlock(&hdev->lock);
1389
1390 if (!ret) {
1391 dev_err(dev, "bad state, cannot suspend\n");
1392 return -EINVAL;
1393 }
1394
1395 ret = venus_prepare_power_collapse(hdev, true);
1396 if (ret) {
1397 dev_err(dev, "prepare for power collapse fail (%d)\n", ret);
1398 return ret;
1399 }
1400
1401 mutex_lock(&hdev->lock);
1402
1403 if (hdev->last_packet_type != HFI_CMD_SYS_PC_PREP) {
1404 mutex_unlock(&hdev->lock);
1405 return -EINVAL;
1406 }
1407
1408 ret = venus_are_queues_empty(hdev);
1409 if (ret < 0 || !ret) {
1410 mutex_unlock(&hdev->lock);
1411 return -EINVAL;
1412 }
1413
1414 ctrl_status = venus_readl(hdev, CPU_CS_SCIACMDARG0);
1415 if (!(ctrl_status & CPU_CS_SCIACMDARG0_PC_READY)) {
1416 mutex_unlock(&hdev->lock);
1417 return -EINVAL;
1418 }
1419
1420 ret = venus_power_off(hdev);
1421 if (ret) {
1422 mutex_unlock(&hdev->lock);
1423 return ret;
1424 }
1425
1426 hdev->suspended = true;
1427
1428 mutex_unlock(&hdev->lock);
1429
1430 return 0;
1431}
1432
1433static int venus_suspend_3xx(struct venus_core *core)
1434{
1435 struct venus_hfi_device *hdev = to_hfi_priv(core);
1436 struct device *dev = core->dev;
1437 u32 ctrl_status, wfi_status;
1438 int ret;
1439 int cnt = 100;
1440
1441 if (!hdev->power_enabled || hdev->suspended)
1442 return 0;
1443
1444 mutex_lock(&hdev->lock);
1445 ret = venus_is_valid_state(hdev);
1446 mutex_unlock(&hdev->lock);
1447
1448 if (!ret) {
1449 dev_err(dev, "bad state, cannot suspend\n");
1450 return -EINVAL;
1451 }
1452
1453 ctrl_status = venus_readl(hdev, CPU_CS_SCIACMDARG0);
1454 if (!(ctrl_status & CPU_CS_SCIACMDARG0_PC_READY)) {
1455 wfi_status = venus_readl(hdev, WRAPPER_CPU_STATUS);
1456 ctrl_status = venus_readl(hdev, CPU_CS_SCIACMDARG0);
1457
1458 ret = venus_prepare_power_collapse(hdev, false);
1459 if (ret) {
1460 dev_err(dev, "prepare for power collapse fail (%d)\n",
1461 ret);
1462 return ret;
1463 }
1464
1465 cnt = 100;
1466 while (cnt--) {
1467 wfi_status = venus_readl(hdev, WRAPPER_CPU_STATUS);
1468 ctrl_status = venus_readl(hdev, CPU_CS_SCIACMDARG0);
1469 if (ctrl_status & CPU_CS_SCIACMDARG0_PC_READY &&
1470 wfi_status & BIT(0))
1471 break;
1472 usleep_range(1000, 1500);
1473 }
1474 }
1475
1476 mutex_lock(&hdev->lock);
1477
1478 ret = venus_power_off(hdev);
1479 if (ret) {
1480 dev_err(dev, "venus_power_off (%d)\n", ret);
1481 mutex_unlock(&hdev->lock);
1482 return ret;
1483 }
1484
1485 hdev->suspended = true;
1486
1487 mutex_unlock(&hdev->lock);
1488
1489 return 0;
1490}
1491
1492static int venus_suspend(struct venus_core *core)
1493{
1494 if (core->res->hfi_version == HFI_VERSION_3XX)
1495 return venus_suspend_3xx(core);
1496
1497 return venus_suspend_1xx(core);
1498}
1499
1500static const struct hfi_ops venus_hfi_ops = {
1501 .core_init = venus_core_init,
1502 .core_deinit = venus_core_deinit,
1503 .core_ping = venus_core_ping,
1504 .core_trigger_ssr = venus_core_trigger_ssr,
1505
1506 .session_init = venus_session_init,
1507 .session_end = venus_session_end,
1508 .session_abort = venus_session_abort,
1509 .session_flush = venus_session_flush,
1510 .session_start = venus_session_start,
1511 .session_stop = venus_session_stop,
1512 .session_continue = venus_session_continue,
1513 .session_etb = venus_session_etb,
1514 .session_ftb = venus_session_ftb,
1515 .session_set_buffers = venus_session_set_buffers,
1516 .session_unset_buffers = venus_session_unset_buffers,
1517 .session_load_res = venus_session_load_res,
1518 .session_release_res = venus_session_release_res,
1519 .session_parse_seq_hdr = venus_session_parse_seq_hdr,
1520 .session_get_seq_hdr = venus_session_get_seq_hdr,
1521 .session_set_property = venus_session_set_property,
1522 .session_get_property = venus_session_get_property,
1523
1524 .resume = venus_resume,
1525 .suspend = venus_suspend,
1526
1527 .isr = venus_isr,
1528 .isr_thread = venus_isr_thread,
1529};
1530
1531void venus_hfi_destroy(struct venus_core *core)
1532{
1533 struct venus_hfi_device *hdev = to_hfi_priv(core);
1534
1535 venus_interface_queues_release(hdev);
1536 mutex_destroy(&hdev->lock);
1537 kfree(hdev);
1538 core->priv = NULL;
1539 core->ops = NULL;
1540}
1541
1542int venus_hfi_create(struct venus_core *core)
1543{
1544 struct venus_hfi_device *hdev;
1545 int ret;
1546
1547 hdev = kzalloc(sizeof(*hdev), GFP_KERNEL);
1548 if (!hdev)
1549 return -ENOMEM;
1550
1551 mutex_init(&hdev->lock);
1552
1553 hdev->core = core;
1554 hdev->suspended = true;
1555 core->priv = hdev;
1556 core->ops = &venus_hfi_ops;
1557 core->core_caps = ENC_ROTATION_CAPABILITY | ENC_SCALING_CAPABILITY |
1558 ENC_DEINTERLACE_CAPABILITY |
1559 DEC_MULTI_STREAM_CAPABILITY;
1560
1561 ret = venus_interface_queues_init(hdev);
1562 if (ret)
1563 goto err_kfree;
1564
1565 return 0;
1566
1567err_kfree:
1568 kfree(hdev);
1569 core->priv = NULL;
1570 core->ops = NULL;
1571 return ret;
1572}
1573