linux/drivers/media/platform/qcom/venus/hfi_venus.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
   3 * Copyright (C) 2017 Linaro Ltd.
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License version 2 and
   7 * only version 2 as published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope that it will be useful,
  10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 * GNU General Public License for more details.
  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;  /* device address */
 113        void *kva;      /* kernel virtual address */
 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        /* serialize read / write to the shared memory */
 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        /* ensure rd/wr indices's are read from memory */
 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                /* ensure tx_req is updated in memory */
 213                wmb();
 214                return -ENOSPC;
 215        }
 216
 217        qhdr->tx_req = 0;
 218        /* ensure tx_req is updated in memory */
 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        /* make sure packet is written before updating the write index */
 235        wmb();
 236
 237        qhdr->write_idx = new_wr_idx;
 238        *rx_req = qhdr->rx_req ? 1 : 0;
 239
 240        /* make sure write index is updated before an interrupt is raised */
 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        /* make sure data is valid before using it */
 269        rmb();
 270
 271        /*
 272         * Do not set receive request for debug queue, if set, Venus generates
 273         * interrupt for debug messages even when there is no response message
 274         * available. In general debug queue will not become full as it is being
 275         * emptied out for every interrupt from Venus. Venus will anyway
 276         * generates interrupt if it is full.
 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                /* update rx_req field in memory */
 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                /* bad packet received, dropping */
 308                new_rd_idx = qhdr->write_idx;
 309                ret = -EBADMSG;
 310        }
 311
 312        /* ensure the packet is read before updating read index */
 313        rmb();
 314
 315        qhdr->read_idx = new_rd_idx;
 316        /* ensure updating read index */
 317        wmb();
 318
 319        rd_idx = qhdr->read_idx;
 320        wr_idx = qhdr->write_idx;
 321        /* ensure rd/wr indices are read from memory */
 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        /* ensure rx_req is stored to memory and tx_req is loaded from memory */
 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         * Re-program all of the registers that get reset as a result of
 506         * regulator_disable() and _enable()
 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        /* Halt AXI and AXI IMEM VBIF Access */
 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        /* Request for AXI bus port halt */
 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         * Set receive request to zero on debug queue as there is no
 749         * need of interrupt from video hardware for debug messages
 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        /* ensure table and queue header structs are settled in memory */
 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         * SFR isn't guaranteed to be NULL terminated since SYS_ERROR indicates
 963         * that Venus is in the process of crashing.
 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         * Once SYS_ERROR received from HW, it is safe to halt the AXI.
 983         * With SYS_ERROR, Venus FW may have crashed and HW might be
 984         * active and causing unnecessary transactions. Hence it is
 985         * safe to stop all AXI transactions from venus subsystem.
 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