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