{"id":818364,"url":"http://patchwork.ozlabs.org/api/patches/818364/?format=json","web_url":"http://patchwork.ozlabs.org/project/devicetree-bindings/patch/5c8b83775b982e6ee851c127444a8e839f422ad0.1506377430.git.digetx@gmail.com/","project":{"id":37,"url":"http://patchwork.ozlabs.org/api/projects/37/?format=json","name":"Devicetree Bindings","link_name":"devicetree-bindings","list_id":"devicetree.vger.kernel.org","list_email":"devicetree@vger.kernel.org","web_url":"","scm_url":"","webscm_url":"","list_archive_url":"","list_archive_url_format":"","commit_url_format":""},"msgid":"<5c8b83775b982e6ee851c127444a8e839f422ad0.1506377430.git.digetx@gmail.com>","list_archive_url":null,"date":"2017-09-25T22:15:42","name":"[v1,1/2] staging: Introduce NVIDIA Tegra20 video decoder driver","commit_ref":null,"pull_url":null,"state":"superseded","archived":true,"hash":"a771f1852ca283ab9f963081fbd87d2ad751cf54","submitter":{"id":18124,"url":"http://patchwork.ozlabs.org/api/people/18124/?format=json","name":"Dmitry Osipenko","email":"digetx@gmail.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/devicetree-bindings/patch/5c8b83775b982e6ee851c127444a8e839f422ad0.1506377430.git.digetx@gmail.com/mbox/","series":[{"id":5020,"url":"http://patchwork.ozlabs.org/api/series/5020/?format=json","web_url":"http://patchwork.ozlabs.org/project/devicetree-bindings/list/?series=5020","date":"2017-09-25T22:15:41","name":"NVIDIA Tegra20 video decoder driver","version":1,"mbox":"http://patchwork.ozlabs.org/series/5020/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/818364/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/818364/checks/","tags":{},"related":[],"headers":{"Return-Path":"<devicetree-owner@vger.kernel.org>","X-Original-To":"incoming-dt@patchwork.ozlabs.org","Delivered-To":"patchwork-incoming-dt@bilbo.ozlabs.org","Authentication-Results":["ozlabs.org;\n\tspf=none (mailfrom) smtp.mailfrom=vger.kernel.org\n\t(client-ip=209.132.180.67; helo=vger.kernel.org;\n\tenvelope-from=devicetree-owner@vger.kernel.org; receiver=<UNKNOWN>)","ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=gmail.com header.i=@gmail.com\n\theader.b=\"PHX/9nM9\"; dkim-atps=neutral"],"Received":["from vger.kernel.org (vger.kernel.org [209.132.180.67])\n\tby ozlabs.org (Postfix) with ESMTP id 3y1JTZ3rlCz9t3R\n\tfor <incoming-dt@patchwork.ozlabs.org>;\n\tTue, 26 Sep 2017 08:21:38 +1000 (AEST)","(majordomo@vger.kernel.org) by vger.kernel.org via listexpand\n\tid S934368AbdIYWVC (ORCPT <rfc822; incoming-dt@patchwork.ozlabs.org>);\n\tMon, 25 Sep 2017 18:21:02 -0400","from mail-wr0-f194.google.com ([209.85.128.194]:38513 \"EHLO\n\tmail-wr0-f194.google.com\" rhost-flags-OK-OK-OK-OK) by vger.kernel.org\n\twith ESMTP id S936021AbdIYWUa (ORCPT\n\t<rfc822; devicetree@vger.kernel.org>); Mon, 25 Sep 2017 18:20:30 -0400","by mail-wr0-f194.google.com with SMTP id p37so813326wrb.5;\n\tMon, 25 Sep 2017 15:20:29 -0700 (PDT)","from localhost.localdomain (ppp109-252-90-109.pppoe.spdop.ru.\n\t[109.252.90.109]) by smtp.gmail.com with ESMTPSA id\n\te2sm1146241lff.61.2017.09.25.15.20.27\n\t(version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128);\n\tMon, 25 Sep 2017 15:20:28 -0700 (PDT)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025;\n\th=from:to:cc:subject:date:message-id:in-reply-to:references\n\t:in-reply-to:references;\n\tbh=u2YvDxb6zpDHMTSmA/GUKbIpHarsbA/mCAtUd/xXp2Q=;\n\tb=PHX/9nM9mSIRKwH1e419s989kCa7Q2OZaz4neKW+kC8vFK3t6QkRK+tznFleV0sJ7p\n\tITW+ioxXbiHtWpX59GaoAiyKqV6GDQEyM4wvfBPIqIhdH/ZM1M/+i+cAE8BZcAVcY5RL\n\tmJSZ/avdRQ4LOMjQW27Qks2EnCoF+aYnVzvCTZ6/Qhq71zIuJqnpNnf+ur17ehIaBpUq\n\ta+Wr3AvI/xwi3UWOwGqIVzXfqY9jBzjn5JBkCfKwUai3diR6whX7A7s5ZFwHkxHxhC2p\n\tWjbE69s12xSpQf0SB8X0R/G8jnx+9mFLe48BYt1M/z4BzwPV82cfXb8NUUW4ankte+fB\n\txhoA==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to\n\t:references:in-reply-to:references;\n\tbh=u2YvDxb6zpDHMTSmA/GUKbIpHarsbA/mCAtUd/xXp2Q=;\n\tb=QRRhUt2wEi252dpogKwMtAjsaIO5Lbc047L+PjnEuLXElOJHnvaGdPySpLav7hkXbn\n\tfk/4gLrfqJWx+v9oXX+V7AJX2dZD1hT3f7mci/dwyrQH3pYtnIHRHZaac0VQ0qyrVn1W\n\tC5wJklCohtXaRDYk4VRJpSGy4ohq/gVEfitvtV6AVmdGImWYMOWjRZzewmZMwMXO08jr\n\tSrO9GyBarUmqbkhaVOkGBr1lHWKHeUWWHFLS80wOBsdVdeON5OlOcf31RoIpm1MH9oyf\n\tWv0aylhUBwTjt4DPq6d26YAoujT59r14revdqAsE06jIYH3+a0JTQhQfFPImKZU5L5C8\n\th5SA==","X-Gm-Message-State":"AHPjjUiPCrE0YonWU8HYMGIpOlhYi96Q+kmkvoheOw6e/Lql/Zh24W0c\n\toh7EiEAJA6YYKuQwWdBydFo=","X-Google-Smtp-Source":"AOwi7QBVTh3IHXisPCpJbtGxEUllDfLR1hyuzFda704Du8fzW1IQzQDJDsNLU/gZGOZQaNRwItrFWg==","X-Received":"by 10.46.4.214 with SMTP id a83mr3207859ljf.61.1506378028734;\n\tMon, 25 Sep 2017 15:20:28 -0700 (PDT)","From":"Dmitry Osipenko <digetx@gmail.com>","To":"Thierry Reding <thierry.reding@gmail.com>,\n\tJonathan Hunter <jonathanh@nvidia.com>,\n\tGreg Kroah-Hartman <gregkh@linuxfoundation.org>,\n\tRob Herring <robh+dt@kernel.org>","Cc":"linux-tegra@vger.kernel.org, devel@driverdev.osuosl.org,\n\tdevicetree@vger.kernel.org, linux-kernel@vger.kernel.org","Subject":"[PATCH v1 1/2] staging: Introduce NVIDIA Tegra20 video decoder\n\tdriver","Date":"Tue, 26 Sep 2017 01:15:42 +0300","Message-Id":"<5c8b83775b982e6ee851c127444a8e839f422ad0.1506377430.git.digetx@gmail.com>","X-Mailer":"git-send-email 2.14.1","In-Reply-To":["<cover.1506377430.git.digetx@gmail.com>","<cover.1506377430.git.digetx@gmail.com>"],"References":["<cover.1506377430.git.digetx@gmail.com>","<cover.1506377430.git.digetx@gmail.com>"],"Sender":"devicetree-owner@vger.kernel.org","Precedence":"bulk","List-ID":"<devicetree.vger.kernel.org>","X-Mailing-List":"devicetree@vger.kernel.org"},"content":"Video decoder, found on NVIDIA Tegra20 SoC, supports a standard set of\nvideo formats like H.264 / MPEG-4 / WMV / VC1. Currently driver supports\ndecoding of CAVLC H.264 only.\n\nSigned-off-by: Dmitry Osipenko <digetx@gmail.com>\n---\n .../bindings/arm/tegra/nvidia,tegra20-vde.txt      |  38 +\n drivers/staging/Kconfig                            |   2 +\n drivers/staging/Makefile                           |   1 +\n drivers/staging/tegra-vde/Kconfig                  |   6 +\n drivers/staging/tegra-vde/Makefile                 |   1 +\n drivers/staging/tegra-vde/TODO                     |   8 +\n drivers/staging/tegra-vde/uapi.h                   |  99 +++\n drivers/staging/tegra-vde/vde.c                    | 971 +++++++++++++++++++++\n 8 files changed, 1126 insertions(+)\n create mode 100644 Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-vde.txt\n create mode 100644 drivers/staging/tegra-vde/Kconfig\n create mode 100644 drivers/staging/tegra-vde/Makefile\n create mode 100644 drivers/staging/tegra-vde/TODO\n create mode 100644 drivers/staging/tegra-vde/uapi.h\n create mode 100644 drivers/staging/tegra-vde/vde.c","diff":"diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-vde.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-vde.txt\nnew file mode 100644\nindex 000000000000..e5ca6f5e96c0\n--- /dev/null\n+++ b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-vde.txt\n@@ -0,0 +1,38 @@\n+NVIDIA Tegra Video Decoder Engine\n+\n+Required properties:\n+- compatible : \"nvidia,tegra20-vde\"\n+- reg : Must contain 2 register ranges: registers and IRAM area.\n+- reg-names : Must include the following entries:\n+  - regs\n+  - iram\n+- interrupts : Must contain an entry for each entry in interrupt-names.\n+- interrupt-names : Must include the following entries:\n+  - ucq-error\n+  - sync-token\n+  - bsev\n+  - bsea\n+  - sxe\n+- clocks : Must contain one entry, for the module clock.\n+  See ../clocks/clock-bindings.txt for details.\n+- resets : Must contain an entry for each entry in reset-names.\n+  See ../reset/reset.txt for details.\n+- reset-names : Must include the following entries:\n+  - vde\n+\n+Example:\n+\tvde@6001a000 {\n+\t\tcompatible = \"nvidia,tegra20-vde\";\n+\t\treg = <0x6001a000 0x3D00    /* VDE registers */\n+\t\t       0x40000400 0x3FC00>; /* IRAM area */\n+\t\treg-names = \"regs\", \"iram\";\n+\t\tinterrupts = <GIC_SPI  8 IRQ_TYPE_LEVEL_HIGH>, /* UCQ error interrupt */\n+\t\t\t     <GIC_SPI  9 IRQ_TYPE_LEVEL_HIGH>, /* Sync token interrupt */\n+\t\t\t     <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>, /* BSE-V interrupt */\n+\t\t\t     <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>, /* BSE-A interrupt */\n+\t\t\t     <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>; /* SXE interrupt */\n+\t\tinterrupt-names = \"ucq-error\", \"sync-token\", \"bsev\", \"bsea\", \"sxe\";\n+\t\tclocks = <&tegra_car TEGRA20_CLK_VDE>;\n+\t\tresets = <&tegra_car 61>;\n+\t\treset-names = \"vde\";\n+\t};\ndiff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig\nindex 554683912cff..10c982811093 100644\n--- a/drivers/staging/Kconfig\n+++ b/drivers/staging/Kconfig\n@@ -118,4 +118,6 @@ source \"drivers/staging/vboxvideo/Kconfig\"\n \n source \"drivers/staging/pi433/Kconfig\"\n \n+source \"drivers/staging/tegra-vde/Kconfig\"\n+\n endif # STAGING\ndiff --git a/drivers/staging/Makefile b/drivers/staging/Makefile\nindex 8951c37d8d80..d07c167d5773 100644\n--- a/drivers/staging/Makefile\n+++ b/drivers/staging/Makefile\n@@ -49,3 +49,4 @@ obj-$(CONFIG_BCM2835_VCHIQ)\t+= vc04_services/\n obj-$(CONFIG_CRYPTO_DEV_CCREE)\t+= ccree/\n obj-$(CONFIG_DRM_VBOXVIDEO)\t+= vboxvideo/\n obj-$(CONFIG_PI433)\t\t+= pi433/\n+obj-$(CONFIG_ARCH_TEGRA)\t+= tegra-vde/\ndiff --git a/drivers/staging/tegra-vde/Kconfig b/drivers/staging/tegra-vde/Kconfig\nnew file mode 100644\nindex 000000000000..b947c012a373\n--- /dev/null\n+++ b/drivers/staging/tegra-vde/Kconfig\n@@ -0,0 +1,6 @@\n+config TEGRA_VDE\n+\ttristate \"NVIDIA Tegra20 video decoder driver\"\n+\tdepends on ARCH_TEGRA_2x_SOC\n+\thelp\n+\t    Say Y here to enable support for a NVIDIA Tegra20 video decoder\n+\t    driver.\ndiff --git a/drivers/staging/tegra-vde/Makefile b/drivers/staging/tegra-vde/Makefile\nnew file mode 100644\nindex 000000000000..e7c0df1174bf\n--- /dev/null\n+++ b/drivers/staging/tegra-vde/Makefile\n@@ -0,0 +1 @@\n+obj-$(CONFIG_TEGRA_VDE)\t+= vde.o\ndiff --git a/drivers/staging/tegra-vde/TODO b/drivers/staging/tegra-vde/TODO\nnew file mode 100644\nindex 000000000000..533ddfc5190e\n--- /dev/null\n+++ b/drivers/staging/tegra-vde/TODO\n@@ -0,0 +1,8 @@\n+All TODO's require reverse-engineering to be done first, it is very\n+unlikely that NVIDIA would ever release HW specs to public.\n+\n+TODO:\n+\t- properly handle decoding faults\n+\t- support more formats\n+\n+Contact: Dmitry Osipenko <digetx@gmail.com>\ndiff --git a/drivers/staging/tegra-vde/uapi.h b/drivers/staging/tegra-vde/uapi.h\nnew file mode 100644\nindex 000000000000..4e60449f688e\n--- /dev/null\n+++ b/drivers/staging/tegra-vde/uapi.h\n@@ -0,0 +1,99 @@\n+/*\n+ * Copyright (C) 2016-2017 Dmitry Osipenko <digetx@gmail.com>\n+ * All Rights Reserved.\n+ *\n+ * Permission is hereby granted, free of charge, to any person obtaining a\n+ * copy of this software and associated documentation files (the \"Software\"),\n+ * to deal in the Software without restriction, including without limitation\n+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,\n+ * and/or sell copies of the Software, and to permit persons to whom the\n+ * Software is furnished to do so, subject to the following conditions:\n+ *\n+ * The above copyright notice and this permission notice (including the next\n+ * paragraph) shall be included in all copies or substantial portions of the\n+ * Software.\n+ *\n+ * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL\n+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR\n+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\n+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n+ * OTHER DEALINGS IN THE SOFTWARE.\n+ */\n+\n+#ifndef _UAPI_TEGRA_VDE_H_\n+#define _UAPI_TEGRA_VDE_H_\n+\n+#include <linux/types.h>\n+#include <asm/ioctl.h>\n+\n+#if defined(__cplusplus)\n+extern \"C\" {\n+#endif\n+\n+#define FLAG_IS_B_FRAME\t\t(1 << 0)\n+#define FLAG_IS_REFERENCE\t(1 << 1)\n+\n+struct tegra_vde_h264_frame {\n+\t__s32 y_fd;\n+\t__s32 cb_fd;\n+\t__s32 cr_fd;\n+\t__s32 aux_fd;\n+\t__u32 y_offset;\n+\t__u32 cb_offset;\n+\t__u32 cr_offset;\n+\t__u32 aux_offset;\n+\t__u32 frame_num;\n+\t__u32 flags;\n+\n+\t__u32 reserved;\n+} __attribute__((packed));\n+\n+struct tegra_vde_h264_decoder_ctx {\n+\t__s32 bitstream_data_fd;\n+\t__u32 bitstream_data_offset;\n+\n+\t__u32 dpb_frames_ptr;\n+\t__u8  dpb_frames_nb;\n+\t__u8  dpb_ref_frames_with_earlier_poc_nb;\n+\n+\t// SPS\n+\t__u8  is_baseline_profile;\n+\t__u8  level_idc;\n+\t__u8  log2_max_pic_order_cnt_lsb;\n+\t__u8  log2_max_frame_num;\n+\t__u8  pic_order_cnt_type;\n+\t__u8  direct_8x8_inference_flag;\n+\t__u8  pic_width_in_mbs;\n+\t__u8  pic_height_in_mbs;\n+\n+\t// PPS\n+\t__u8  pic_init_qp;\n+\t__u8  deblocking_filter_control_present_flag;\n+\t__u8  constrained_intra_pred_flag;\n+\t__u8  chroma_qp_index_offset;\n+\t__u8  pic_order_present_flag;\n+\n+\t// Slice header\n+\t__u8  num_ref_idx_l0_active_minus1;\n+\t__u8  num_ref_idx_l1_active_minus1;\n+\n+\t__u32 reserved;\n+} __attribute__((packed));\n+\n+#define VDE_IOCTL_BASE\t\t\t'v'\n+#define VDE_IO(nr)\t\t\t_IO(VDE_IOCTL_BASE,nr)\n+#define VDE_IOR(nr,type)\t\t_IOR(VDE_IOCTL_BASE,nr,type)\n+#define VDE_IOW(nr,type)\t\t_IOW(VDE_IOCTL_BASE,nr,type)\n+#define VDE_IOWR(nr,type)\t\t_IOWR(VDE_IOCTL_BASE,nr,type)\n+\n+#define TEGRA_VDE_DECODE_H264\t\t0x01\n+\n+#define TEGRA_VDE_IOCTL_DECODE_H264\tVDE_IOW(VDE_IOCTL_BASE + TEGRA_VDE_DECODE_H264, struct tegra_vde_h264_decoder_ctx)\n+\n+#if defined(__cplusplus)\n+}\n+#endif\n+\n+#endif // _UAPI_TEGRA_VDE_H_\ndiff --git a/drivers/staging/tegra-vde/vde.c b/drivers/staging/tegra-vde/vde.c\nnew file mode 100644\nindex 000000000000..309d87926e21\n--- /dev/null\n+++ b/drivers/staging/tegra-vde/vde.c\n@@ -0,0 +1,971 @@\n+/*\n+ * NVIDIA Tegra20 Video decoder driver\n+ *\n+ * Copyright (C) 2016-2017 Dmitry Osipenko <digetx@gmail.com>\n+ *\n+ * This program is free software; you can redistribute it and/or modify it\n+ * under the terms of the GNU General Public License version 2 as published by\n+ * the Free Software Foundation.\n+ */\n+\n+#include <linux/clk.h>\n+#include <linux/delay.h>\n+#include <linux/dma-buf.h>\n+#include <linux/interrupt.h>\n+#include <linux/io.h>\n+#include <linux/iopoll.h>\n+#include <linux/miscdevice.h>\n+#include <linux/module.h>\n+#include <linux/platform_device.h>\n+#include <linux/reset.h>\n+#include <linux/slab.h>\n+#include <linux/uaccess.h>\n+\n+#include <soc/tegra/pmc.h>\n+\n+#include \"uapi.h\"\n+\n+#define SXE(offt)\t\t(0x0000 + (offt))\n+#define BSEV(offt)\t\t(0x1000 + (offt))\n+#define MBE(offt)\t\t(0x2000 + (offt))\n+#define PPE(offt)\t\t(0x2200 + (offt))\n+#define MCE(offt)\t\t(0x2400 + (offt))\n+#define TFE(offt)\t\t(0x2600 + (offt))\n+#define VDMA(offt)\t\t(0x2A00 + (offt))\n+#define FRAMEID(offt)\t\t(0x3800 + (offt))\n+\n+#define ICMDQUE_WR\t\t0x00\n+#define CMDQUE_CONTROL\t\t0x08\n+#define INTR_STATUS\t\t0x18\n+#define BSE_INT_ENB\t\t0x40\n+#define BSE_CONFIG\t\t0x44\n+\n+#define BSE_ICMDQUE_EMPTY\tBIT(3)\n+#define BSE_DMA_BUSY\t\tBIT(23)\n+\n+#define TEGRA_VDE_TIMEOUT\t(msecs_to_jiffies(1000))\n+\n+#define VDE_WR(data, addr)\t\t\t\t\\\n+do {\t\t\t\t\t\t\t\\\n+\tpr_debug(\"%s: %d: 0x%08X => \" #addr \")\\n\",\t\\\n+\t\t  __func__, __LINE__, (data));\t\t\\\n+\twritel_relaxed(data, addr);\t\t\t\\\n+} while (0)\n+\n+struct video_frame {\n+\tstruct dma_buf_attachment *y_dmabuf_attachment;\n+\tstruct dma_buf_attachment *cb_dmabuf_attachment;\n+\tstruct dma_buf_attachment *cr_dmabuf_attachment;\n+\tstruct dma_buf_attachment *aux_dmabuf_attachment;\n+\tdma_addr_t y_paddr;\n+\tdma_addr_t cb_paddr;\n+\tdma_addr_t cr_paddr;\n+\tdma_addr_t aux_paddr;\n+\tu32 frame_num;\n+\tu32 flags;\n+};\n+\n+struct tegra_vde {\n+\tvoid __iomem *regs;\n+\tvoid __iomem *iram;\n+\tstruct mutex lock;\n+\tstruct miscdevice miscdev;\n+\tstruct reset_control *rst;\n+\tstruct clk *clk;\n+\tstruct completion decode_completion;\n+\tphys_addr_t iram_lists_paddr;\n+\tint irq;\n+};\n+\n+static void tegra_vde_set_bits(void __iomem *regs, u32 mask, u32 offset)\n+{\n+\tu32 value = readl_relaxed(regs + offset);\n+\n+\tVDE_WR(value | mask, regs + offset);\n+}\n+\n+static int tegra_vde_wait_mbe(void __iomem *regs)\n+{\n+\tu32 tmp;\n+\n+\treturn readl_poll_timeout(regs + MBE(0x8C), tmp, (tmp >= 0x10), 1, 100);\n+}\n+\n+static int tegra_vde_setup_mbe_frame_idx(void __iomem *regs,\n+\t\t\t\t\t int setup_refs, int refs_nb)\n+{\n+\tu32 frame_idx_enb_mask = 0;\n+\tu32 value;\n+\tint frame_idx;\n+\tint idx;\n+\n+\tVDE_WR(0xD0000000 | (0 << 23), regs + MBE(0x80));\n+\tVDE_WR(0xD0200000 | (0 << 23), regs + MBE(0x80));\n+\n+\tif (tegra_vde_wait_mbe(regs))\n+\t\treturn -EIO;\n+\n+\tif (!setup_refs)\n+\t\treturn 0;\n+\n+\tfor (idx = 0, frame_idx = 1; idx < refs_nb; idx++, frame_idx++) {\n+\t\tVDE_WR(0xD0000000 | (frame_idx << 23), regs + MBE(0x80));\n+\t\tVDE_WR(0xD0200000 | (frame_idx << 23), regs + MBE(0x80));\n+\n+\t\tframe_idx_enb_mask |= frame_idx << (6 * (idx % 4));\n+\n+\t\tif (idx % 4 == 3 || idx == refs_nb - 1) {\n+\t\t\tvalue = 0xC0000000;\n+\t\t\tvalue |= (idx >> 2) << 24;\n+\t\t\tvalue |= frame_idx_enb_mask;\n+\n+\t\t\tVDE_WR(value, regs + MBE(0x80));\n+\n+\t\t\tif (tegra_vde_wait_mbe(regs))\n+\t\t\t\treturn -EIO;\n+\n+\t\t\tframe_idx_enb_mask = 0;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static void tegra_vde_mbe_set_0xa_reg(void __iomem *regs, int reg, u32 val)\n+{\n+\tVDE_WR(0xA0000000 | (reg << 24) | (val & 0xFFFF), regs + MBE(0x80));\n+\tVDE_WR(0xA0000000 | ((reg + 1) << 24) | (val >> 16), regs + MBE(0x80));\n+}\n+\n+static int tegra_vde_wait_bsev(struct tegra_vde *vde, bool wait_dma)\n+{\n+\tstruct device *dev = vde->miscdev.parent;\n+\tu32 polled;\n+\tint ret;\n+\n+\tret = readl_poll_timeout(vde->regs + BSEV(INTR_STATUS), polled,\n+\t\t\t\t !(polled & BIT(2)), 1, 100);\n+\tif (ret) {\n+\t\tdev_err(dev, \"BSEV unknown bit timeout\\n\");\n+\t\treturn -EIO;\n+\t}\n+\n+\tret = readl_poll_timeout(vde->regs + BSEV(INTR_STATUS), polled,\n+\t\t\t\t (polled & BSE_ICMDQUE_EMPTY), 1, 100);\n+\tif (ret) {\n+\t\tdev_err(dev, \"BSEV ICMDQUE flush timeout\\n\");\n+\t\treturn -EIO;\n+\t}\n+\n+\tif (!wait_dma)\n+\t\treturn 0;\n+\n+\tret = readl_poll_timeout(vde->regs + BSEV(INTR_STATUS), polled,\n+\t\t\t\t !(polled & BSE_DMA_BUSY), 1, 100);\n+\tif (ret) {\n+\t\tdev_err(dev, \"BSEV DMA timeout\\n\");\n+\t\treturn -EIO;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int tegra_vde_push_bsev_icmdqueue(struct tegra_vde *vde,\n+\t\t\t\t\t u32 value, bool wait_dma)\n+{\n+\tVDE_WR(value, vde->regs + BSEV(ICMDQUE_WR));\n+\n+\treturn tegra_vde_wait_bsev(vde, wait_dma);\n+}\n+\n+static void tegra_vde_setup_frameid(void __iomem *regs,\n+\t\t\t\t    struct video_frame *frame, int frameid,\n+\t\t\t\t    u32 mbs_width, u32 mbs_height)\n+{\n+\tu32 y_paddr  = frame ? frame->y_paddr  : 0xFCDEAD00;\n+\tu32 cb_paddr = frame ? frame->cb_paddr : 0xFCDEAD00;\n+\tu32 cr_paddr = frame ? frame->cr_paddr : 0xFCDEAD00;\n+\tu32 v1 = frame ? ((mbs_width << 16) | mbs_height) : 0;\n+\tu32 v2 = frame ? ((((mbs_width + 1) >> 1) << 6) | 1) : 0;\n+\n+\tVDE_WR( y_paddr >> 8, regs + FRAMEID(0x000 + frameid * 4));\n+\tVDE_WR(cb_paddr >> 8, regs + FRAMEID(0x100 + frameid * 4));\n+\tVDE_WR(cr_paddr >> 8, regs + FRAMEID(0x180 + frameid * 4));\n+\tVDE_WR(v1,            regs + FRAMEID(0x080 + frameid * 4));\n+\tVDE_WR(v2,            regs + FRAMEID(0x280 + frameid * 4));\n+}\n+\n+static void tegra_setup_frameidx(void __iomem *regs,\n+\t\t\t\t struct video_frame *frames, int frames_nb,\n+\t\t\t\t u32 mbs_width, u32 mbs_height)\n+{\n+\tint idx;\n+\n+\tfor (idx = 0; idx < frames_nb; idx++)\n+\t\ttegra_vde_setup_frameid(regs, &frames[idx], idx,\n+\t\t\t\t\tmbs_width, mbs_height);\n+\tfor (; idx < 17; idx++)\n+\t\ttegra_vde_setup_frameid(regs, NULL, idx, 0, 0);\n+}\n+\n+static void tegra_vde_write_iram_entry(void __iomem *tables,\n+\t\t\t\t       int table, int row,\n+\t\t\t\t       u32 value1, u32 value2)\n+{\n+\tVDE_WR(value1, tables + 0x80 * table + row * 8);\n+\tVDE_WR(value2, tables + 0x80 * table + row * 8 + 4);\n+}\n+\n+static void tegra_vde_setup_iram_tables(void __iomem *iram_tables,\n+\t\t\t\t\tstruct video_frame *dpb_frames,\n+\t\t\t\t\tint ref_frames_nb,\n+\t\t\t\t\tint with_earlier_poc_nb)\n+{\n+\tstruct video_frame *frame;\n+\tu32 value, aux_paddr;\n+\tint with_later_poc_nb;\n+\tint i, k;\n+\n+\tpr_debug(\"DPB: Frame 0: frame_num = %d\\n\", dpb_frames[0].frame_num);\n+\n+\tpr_debug(\"REF L0:\\n\");\n+\n+\tfor (i = 0; i < 16; i++) {\n+\t\tif (i < ref_frames_nb) {\n+\t\t\tframe = &dpb_frames[i + 1];\n+\n+\t\t\taux_paddr = frame->aux_paddr;\n+\n+\t\t\tvalue  = (i + 1) << 26;\n+\t\t\tvalue |= !(frame->flags & FLAG_IS_B_FRAME) << 25;\n+\t\t\tvalue |= 1 << 24;\n+\t\t\tvalue |= frame->frame_num;\n+\n+\t\t\tpr_debug(\"\\tFrame %d: frame_num = %d is_B_frame = %d\\n\",\n+\t\t\t\t i + 1, frame->frame_num,\n+\t\t\t\t (frame->flags & FLAG_IS_B_FRAME));\n+\t\t} else {\n+\t\t\taux_paddr = 0xFADEAD00;\n+\t\t\tvalue = 0;\n+\t\t}\n+\n+\t\ttegra_vde_write_iram_entry(iram_tables, 0, i, value, aux_paddr);\n+\t\ttegra_vde_write_iram_entry(iram_tables, 1, i, value, aux_paddr);\n+\t\ttegra_vde_write_iram_entry(iram_tables, 2, i, value, aux_paddr);\n+\t\ttegra_vde_write_iram_entry(iram_tables, 3, i, value, aux_paddr);\n+\t}\n+\n+\tif (!(dpb_frames[0].flags & FLAG_IS_B_FRAME))\n+\t\treturn;\n+\n+\tif (with_earlier_poc_nb >= ref_frames_nb)\n+\t\treturn;\n+\n+\twith_later_poc_nb = ref_frames_nb - with_earlier_poc_nb;\n+\n+\tpr_debug(\"REF L1: with_later_poc_nb %d with_earlier_poc_nb %d\\n\",\n+\t\t with_later_poc_nb, with_earlier_poc_nb);\n+\n+\tfor (i = 0, k = with_earlier_poc_nb; i < with_later_poc_nb; i++, k++) {\n+\t\tframe = &dpb_frames[k + 1];\n+\n+\t\taux_paddr = frame->aux_paddr;\n+\n+\t\tvalue  = (k + 1) << 26;\n+\t\tvalue |= !(frame->flags & FLAG_IS_B_FRAME) << 25;\n+\t\tvalue |= 1 << 24;\n+\t\tvalue |= frame->frame_num;\n+\n+\t\tpr_debug(\"\\tFrame %d: frame_num = %d\\n\",\n+\t\t\t k + 1, frame->frame_num);\n+\n+\t\ttegra_vde_write_iram_entry(iram_tables, 2, i, value, aux_paddr);\n+\t}\n+\n+\tfor (k = 0; i < ref_frames_nb; i++, k++) {\n+\t\tframe = &dpb_frames[k + 1];\n+\n+\t\taux_paddr = frame->aux_paddr;\n+\n+\t\tvalue  = (k + 1) << 26;\n+\t\tvalue |= !(frame->flags & FLAG_IS_B_FRAME) << 25;\n+\t\tvalue |= 1 << 24;\n+\t\tvalue |= frame->frame_num;\n+\n+\t\tpr_debug(\"\\tFrame %d: frame_num = %d\\n\",\n+\t\t\t k + 1, frame->frame_num);\n+\n+\t\ttegra_vde_write_iram_entry(iram_tables, 2, i, value, aux_paddr);\n+\t}\n+}\n+\n+static int tegra_vde_setup_context(struct tegra_vde *vde,\n+\t\t\t\t   struct tegra_vde_h264_decoder_ctx *ctx,\n+\t\t\t\t   struct video_frame *dpb_frames,\n+\t\t\t\t   phys_addr_t bitstream_data_paddr,\n+\t\t\t\t   int bitstream_data_size,\n+\t\t\t\t   int macroblocks_nb)\n+{\n+\tstruct device *dev = vde->miscdev.parent;\n+\tu32 value;\n+\n+\ttegra_vde_set_bits(vde->regs,    0xA, SXE(0xF0));\n+\ttegra_vde_set_bits(vde->regs,    0xB, BSEV(CMDQUE_CONTROL));\n+\ttegra_vde_set_bits(vde->regs, 0x8002, MBE(0x50));\n+\ttegra_vde_set_bits(vde->regs,    0xA, MBE(0xA0));\n+\ttegra_vde_set_bits(vde->regs,    0xA, PPE(0x14));\n+\ttegra_vde_set_bits(vde->regs,    0xA, PPE(0x28));\n+\ttegra_vde_set_bits(vde->regs,  0xA00, MCE(0x08));\n+\ttegra_vde_set_bits(vde->regs,    0xA, TFE(0x00));\n+\ttegra_vde_set_bits(vde->regs,    0x5, VDMA(0x04));\n+\n+\tVDE_WR(0x00000000, vde->regs + VDMA(0x1C));\n+\tVDE_WR(0x00000000, vde->regs + VDMA(0x00));\n+\tVDE_WR(0x00000007, vde->regs + VDMA(0x04));\n+\tVDE_WR(0x00000007, vde->regs + FRAMEID(0x200));\n+\tVDE_WR(0x00000005, vde->regs + TFE(0x04));\n+\tVDE_WR(0x00000000, vde->regs + MBE(0x84));\n+\tVDE_WR(0x00000010, vde->regs + SXE(0x08));\n+\tVDE_WR(0x00000150, vde->regs + SXE(0x54));\n+\tVDE_WR(0x0000054C, vde->regs + SXE(0x58));\n+\tVDE_WR(0x00000E34, vde->regs + SXE(0x5C));\n+\tVDE_WR(0x063C063C, vde->regs + MCE(0x10));\n+\tVDE_WR(0x0003FC00, vde->regs + BSEV(INTR_STATUS));\n+\tVDE_WR(0x0000150D, vde->regs + BSEV(BSE_CONFIG));\n+\tVDE_WR(0x00000100, vde->regs + BSEV(BSE_INT_ENB));\n+\tVDE_WR(0x00000000, vde->regs + BSEV(0x98));\n+\tVDE_WR(0x00000060, vde->regs + BSEV(0x9C));\n+\n+\tmemset_io(vde->iram + 512, 0, macroblocks_nb / 2);\n+\n+\ttegra_setup_frameidx(vde->regs, dpb_frames, ctx->dpb_frames_nb,\n+\t\t\t     ctx->pic_width_in_mbs, ctx->pic_height_in_mbs);\n+\n+\ttegra_vde_setup_iram_tables(vde->iram, dpb_frames,\n+\t\t\t\t    ctx->dpb_frames_nb - 1,\n+\t\t\t\t    ctx->dpb_ref_frames_with_earlier_poc_nb);\n+\n+\tVDE_WR(0x00000000, vde->regs + BSEV(0x8C));\n+\tVDE_WR(bitstream_data_paddr + bitstream_data_size,\n+\t       vde->regs + BSEV(0x54));\n+\n+\tvalue = ctx->pic_width_in_mbs << 11 | ctx->pic_height_in_mbs << 3;\n+\n+\tVDE_WR(value, vde->regs + BSEV(0x88));\n+\n+\tif (tegra_vde_wait_bsev(vde, false))\n+\t\treturn -EIO;\n+\n+\tif (tegra_vde_push_bsev_icmdqueue(vde, 0x800003FC, false))\n+\t\treturn -EIO;\n+\n+\tvalue = 0x01500000;\n+\tvalue |= ((vde->iram_lists_paddr + 512) >> 2) & 0xFFFF;\n+\n+\tif (tegra_vde_push_bsev_icmdqueue(vde, value, true))\n+\t\treturn -EIO;\n+\n+\tif (tegra_vde_push_bsev_icmdqueue(vde, 0x840F054C, false))\n+\t\treturn -EIO;\n+\n+\tif (tegra_vde_push_bsev_icmdqueue(vde, 0x80000080, false))\n+\t\treturn -EIO;\n+\n+\tvalue = 0x0E340000 | ((vde->iram_lists_paddr >> 2) & 0xFFFF);\n+\n+\tif (tegra_vde_push_bsev_icmdqueue(vde, value, true))\n+\t\treturn -EIO;\n+\n+\tvalue = (1 << 23) | 5;\n+\tvalue |= ctx->pic_width_in_mbs << 11;\n+\tvalue |= ctx->pic_height_in_mbs << 3;\n+\n+\tVDE_WR(value, vde->regs + SXE(0x10));\n+\n+\tvalue = !ctx->is_baseline_profile << 17;\n+\tvalue |= ctx->level_idc << 13;\n+\tvalue |= ctx->log2_max_pic_order_cnt_lsb << 7;\n+\tvalue |= ctx->pic_order_cnt_type << 5;\n+\tvalue |= ctx->log2_max_frame_num;\n+\n+\tVDE_WR(value, vde->regs + SXE(0x40));\n+\n+\tvalue = ctx->pic_init_qp << 25;\n+\tvalue |= !!(ctx->deblocking_filter_control_present_flag) << 2;\n+\tvalue |= !!ctx->pic_order_present_flag;\n+\n+\tVDE_WR(value, vde->regs + SXE(0x44));\n+\n+\tvalue = ctx->chroma_qp_index_offset;\n+\tvalue |= ctx->num_ref_idx_l0_active_minus1 << 5;\n+\tvalue |= ctx->num_ref_idx_l1_active_minus1 << 10;\n+\tvalue |= !!ctx->constrained_intra_pred_flag << 15;\n+\n+\tVDE_WR(value, vde->regs + SXE(0x48));\n+\n+\tvalue = 0x0C000000;\n+\tvalue |= !!(dpb_frames[0].flags & FLAG_IS_B_FRAME) << 24;\n+\n+\tVDE_WR(value, vde->regs + SXE(0x4C));\n+\n+\tvalue = 0x03800000;\n+\tvalue |= min(bitstream_data_size, SZ_1M);\n+\n+\tVDE_WR(value, vde->regs + SXE(0x68));\n+\n+\tVDE_WR(bitstream_data_paddr, vde->regs + SXE(0x6C));\n+\n+\tvalue = (1 << 28) | 5;\n+\tvalue |= ctx->pic_width_in_mbs << 11;\n+\tvalue |= ctx->pic_height_in_mbs << 3;\n+\n+\tVDE_WR(value, vde->regs + MBE(0x80));\n+\n+\tvalue = 0x26800000;\n+\tvalue |= ctx->level_idc << 4;\n+\tvalue |= !ctx->is_baseline_profile << 1;\n+\tvalue |= !!ctx->direct_8x8_inference_flag;\n+\n+\tVDE_WR(value, vde->regs + MBE(0x80));\n+\n+\tVDE_WR(0xF4000001, vde->regs + MBE(0x80));\n+\tVDE_WR(0x20000000, vde->regs + MBE(0x80));\n+\tVDE_WR(0xF4000101, vde->regs + MBE(0x80));\n+\n+\tvalue = 0x20000000;\n+\tvalue |= ctx->chroma_qp_index_offset << 8;\n+\n+\tVDE_WR(value, vde->regs + MBE(0x80));\n+\n+\tif (tegra_vde_setup_mbe_frame_idx(vde->regs,\n+\t\t\t\t\t  ctx->pic_order_cnt_type == 0,\n+\t\t\t\t\t  ctx->dpb_frames_nb - 1)) {\n+\t\tdev_err(dev, \"MBE frames setup failed\\n\");\n+\t\treturn -EIO;\n+\t}\n+\n+\ttegra_vde_mbe_set_0xa_reg(vde->regs, 0, 0x000009FC);\n+\ttegra_vde_mbe_set_0xa_reg(vde->regs, 2, 0xF1DEAD00);\n+\ttegra_vde_mbe_set_0xa_reg(vde->regs, 4, 0xF2DEAD00);\n+\ttegra_vde_mbe_set_0xa_reg(vde->regs, 6, 0xF3DEAD00);\n+\ttegra_vde_mbe_set_0xa_reg(vde->regs, 8, dpb_frames[0].aux_paddr);\n+\n+\tvalue = 0xFC000000;\n+\tvalue |= !!(dpb_frames[0].flags & FLAG_IS_B_FRAME) << 2;\n+\n+\tif (!ctx->is_baseline_profile)\n+\t\tvalue |= !!(dpb_frames[0].flags & FLAG_IS_REFERENCE) << 1;\n+\n+\tVDE_WR(value, vde->regs + MBE(0x80));\n+\n+\tif (tegra_vde_wait_mbe(vde->regs)) {\n+\t\tdev_err(dev, \"MBE programming failed\\n\");\n+\t\treturn -EIO;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static void tegra_vde_decode_frame(struct tegra_vde *vde, int macroblocks_nb)\n+{\n+\tVDE_WR(0x00000001, vde->regs + BSEV(0x8C));\n+\tVDE_WR(0x20000000 | (macroblocks_nb - 1), vde->regs + SXE(0x00));\n+}\n+\n+static void tegra_vde_detach_and_put_dmabuf(struct dma_buf_attachment *a)\n+{\n+\tstruct dma_buf *dmabuf = a->dmabuf;\n+\n+\tif (IS_ERR_OR_NULL(a))\n+\t\treturn;\n+\n+\tdma_buf_detach(dmabuf, a);\n+\tdma_buf_put(dmabuf);\n+}\n+\n+static int tegra_vde_attach_dmabuf(struct device *dev, int fd,\n+\t\t\t\t   unsigned long offset, int min_size,\n+\t\t\t\t   struct dma_buf_attachment **a,\n+\t\t\t\t   phys_addr_t *paddr, u32 *size,\n+\t\t\t\t   enum dma_data_direction dma_dir)\n+{\n+\tstruct dma_buf_attachment *attachment;\n+\tstruct dma_buf *dmabuf;\n+\tstruct sg_table *sgt;\n+\n+\t*a = NULL;\n+\t*paddr = 0xFBDEAD00;\n+\n+\tdmabuf = dma_buf_get(fd);\n+\tif (IS_ERR(dmabuf)) {\n+\t\tdev_err(dev, \"Invalid dmabuf FD\\n\");\n+\t\treturn PTR_ERR(dmabuf);\n+\t}\n+\n+\tif ((u64)offset + min_size > dmabuf->size) {\n+\t\tdev_err(dev, \"Too small dmabuf size %d @0x%lX, \"\n+\t\t\t     \"should be at least %d\\n\",\n+\t\t\tdmabuf->size, offset, min_size);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tattachment = dma_buf_attach(dmabuf, dev);\n+\tif (IS_ERR(attachment)) {\n+\t\tdev_err(dev, \"Failed to attach dmabuf\\n\");\n+\t\tdma_buf_put(dmabuf);\n+\t\treturn PTR_ERR(attachment);\n+\t}\n+\n+\tsgt = dma_buf_map_attachment(attachment, dma_dir);\n+\tif (IS_ERR(sgt)) {\n+\t\tdev_err(dev, \"Failed to get dmabuf sg_table\\n\");\n+\t\tdma_buf_detach(dmabuf, attachment);\n+\t\tdma_buf_put(dmabuf);\n+\t\treturn PTR_ERR(sgt);\n+\t}\n+\n+\tif (sgt->nents != 1) {\n+\t\tdev_err(dev, \"Sparsed DMA area is unsupported\\n\");\n+\t\tdma_buf_unmap_attachment(attachment, sgt, dma_dir);\n+\t\tdma_buf_detach(dmabuf, attachment);\n+\t\tdma_buf_put(dmabuf);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t*paddr = sg_dma_address(sgt->sgl) + offset;\n+\n+\tdma_buf_unmap_attachment(attachment, sgt, dma_dir);\n+\n+\t*a = attachment;\n+\n+\tif (size)\n+\t\t*size = dmabuf->size - offset;\n+\n+\treturn 0;\n+}\n+\n+static int tegra_vde_attach_frame_dmabufs(struct device *dev,\n+\t\t\t\t\t  struct video_frame *frame,\n+\t\t\t\t\t  struct tegra_vde_h264_frame *source,\n+\t\t\t\t\t  enum dma_data_direction dma_dir,\n+\t\t\t\t\t  int is_baseline_profile, int csize)\n+{\n+\tint ret;\n+\n+\tret = tegra_vde_attach_dmabuf(dev, source->y_fd,\n+\t\t\t\t      source->y_offset, csize * 4,\n+\t\t\t\t      &frame->y_dmabuf_attachment,\n+\t\t\t\t      &frame->y_paddr, NULL, dma_dir);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = tegra_vde_attach_dmabuf(dev, source->cb_fd,\n+\t\t\t\t      source->cb_offset, csize,\n+\t\t\t\t      &frame->cb_dmabuf_attachment,\n+\t\t\t\t      &frame->cb_paddr, NULL, dma_dir);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = tegra_vde_attach_dmabuf(dev, source->cr_fd,\n+\t\t\t\t      source->cr_offset, csize,\n+\t\t\t\t      &frame->cr_dmabuf_attachment,\n+\t\t\t\t      &frame->cr_paddr, NULL, dma_dir);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tif (is_baseline_profile)\n+\t\tframe->aux_paddr = 0xF4DEAD00;\n+\telse\n+\t\tret = tegra_vde_attach_dmabuf(dev, source->aux_fd,\n+\t\t\t\t\t      source->aux_offset, csize,\n+\t\t\t\t\t      &frame->aux_dmabuf_attachment,\n+\t\t\t\t\t      &frame->aux_paddr, NULL, dma_dir);\n+\n+\treturn ret;\n+}\n+\n+static void tegra_vde_deattach_frame_dmabufs(struct video_frame *frame)\n+{\n+\ttegra_vde_detach_and_put_dmabuf(frame->y_dmabuf_attachment);\n+\ttegra_vde_detach_and_put_dmabuf(frame->cb_dmabuf_attachment);\n+\ttegra_vde_detach_and_put_dmabuf(frame->cr_dmabuf_attachment);\n+\ttegra_vde_detach_and_put_dmabuf(frame->aux_dmabuf_attachment);\n+}\n+\n+static int tegra_vde_copy_and_validate_frame(struct device *dev,\n+\t\t\t\t\t     struct tegra_vde_h264_frame *frame,\n+\t\t\t\t\t     unsigned long vaddr)\n+{\n+\tif (copy_from_user(frame, (void __user *)vaddr, sizeof(*frame))) {\n+\t\tdev_err(dev, \"Copying of H.264 frame from user failed\\n\");\n+\t\treturn -EFAULT;\n+\t}\n+\n+\tif (frame->frame_num > 0x7FFFFF) {\n+\t\tdev_err(dev, \"Bad frame_num %u\\n\", frame->frame_num);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (frame->y_offset & 0xFF) {\n+\t\tdev_err(dev, \"Bad y_offset 0x%X\\n\", frame->y_offset);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (frame->cb_offset & 0xFF) {\n+\t\tdev_err(dev, \"Bad cb_offset 0x%X\\n\", frame->cb_offset);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (frame->cr_offset & 0xFF) {\n+\t\tdev_err(dev, \"Bad cr_offset 0x%X\\n\", frame->cr_offset);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int tegra_vde_validate_h264_ctx(struct device *dev,\n+\t\t\t\t       struct tegra_vde_h264_decoder_ctx *ctx)\n+{\n+\tif (ctx->dpb_frames_nb == 0 || ctx->dpb_frames_nb > 17) {\n+\t\tdev_err(dev, \"Bad DPB size %u\\n\", ctx->dpb_frames_nb);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (ctx->level_idc > 15) {\n+\t\tdev_err(dev, \"Bad level value %u\\n\", ctx->level_idc);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (ctx->pic_init_qp > 52) {\n+\t\tdev_err(dev, \"Bad pic_init_qp value %u\\n\", ctx->pic_init_qp);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (ctx->log2_max_pic_order_cnt_lsb > 16) {\n+\t\tdev_err(dev, \"Bad log2_max_pic_order_cnt_lsb value %u\\n\",\n+\t\t\tctx->log2_max_pic_order_cnt_lsb);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (ctx->log2_max_frame_num > 16) {\n+\t\tdev_err(dev, \"Bad log2_max_frame_num value %u\\n\",\n+\t\t\tctx->log2_max_frame_num);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (ctx->chroma_qp_index_offset > 31) {\n+\t\tdev_err(dev, \"Bad chroma_qp_index_offset value %u\\n\",\n+\t\t\tctx->chroma_qp_index_offset);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (ctx->pic_order_cnt_type > 2) {\n+\t\tdev_err(dev, \"Bad pic_order_cnt_type value %u\\n\",\n+\t\t\tctx->pic_order_cnt_type);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (ctx->num_ref_idx_l0_active_minus1 > 15) {\n+\t\tdev_err(dev, \"Bad num_ref_idx_l0_active_minus1 value %u\\n\",\n+\t\t\tctx->num_ref_idx_l0_active_minus1);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (ctx->num_ref_idx_l1_active_minus1 > 15) {\n+\t\tdev_err(dev, \"Bad num_ref_idx_l1_active_minus1 value %u\\n\",\n+\t\t\tctx->num_ref_idx_l1_active_minus1);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (!ctx->pic_width_in_mbs || ctx->pic_width_in_mbs > 127) {\n+\t\tdev_err(dev, \"Bad pic_width_in_mbs value %u, min 1 max 127\\n\",\n+\t\t\tctx->pic_width_in_mbs);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (!ctx->pic_height_in_mbs || ctx->pic_height_in_mbs > 127) {\n+\t\tdev_err(dev, \"Bad pic_height_in_mbs value %u, min 1 max 127\\n\",\n+\t\t\tctx->pic_height_in_mbs);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int tegra_vde_ioctl_decode_h264(struct tegra_vde *vde,\n+\t\t\t\t       unsigned long vaddr)\n+{\n+\tstruct tegra_vde_h264_decoder_ctx ctx;\n+\tstruct tegra_vde_h264_frame frame;\n+\tstruct device *dev = vde->miscdev.parent;\n+\tstruct video_frame *dpb_frames = NULL;\n+\tstruct dma_buf_attachment *bitstream_data_dmabuf_attachment = NULL;\n+\tenum dma_data_direction dma_dir;\n+\tphys_addr_t bitstream_data_paddr;\n+\tphys_addr_t bsev_paddr;\n+\tu32 bitstream_data_size;\n+\tu32 macroblocks_nb;\n+\tbool timeout = false;\n+\tint i, ret;\n+\n+\tif (copy_from_user(&ctx, (void __user *)vaddr, sizeof(ctx))) {\n+\t\tdev_err(dev, \"Copying of H.264 CTX from user failed\\n\");\n+\t\treturn -EFAULT;\n+\t}\n+\n+\tret = tegra_vde_validate_h264_ctx(dev, &ctx);\n+\tif (ret)\n+\t\treturn -EINVAL;\n+\n+\tret = tegra_vde_attach_dmabuf(dev, ctx.bitstream_data_fd,\n+\t\t\t\t      ctx.bitstream_data_offset, 0,\n+\t\t\t\t      &bitstream_data_dmabuf_attachment,\n+\t\t\t\t      &bitstream_data_paddr,\n+\t\t\t\t      &bitstream_data_size,\n+\t\t\t\t      DMA_TO_DEVICE);\n+\tif (ret)\n+\t\tgoto cleanup;\n+\n+\tdpb_frames = kcalloc(ctx.dpb_frames_nb, sizeof(*dpb_frames),\n+\t\t\t     GFP_KERNEL);\n+\tif (!dpb_frames) {\n+\t\tret = -ENOMEM;\n+\t\tgoto cleanup;\n+\t}\n+\n+\tmacroblocks_nb = ctx.pic_width_in_mbs * ctx.pic_height_in_mbs;\n+\tvaddr = ctx.dpb_frames_ptr;\n+\n+\tfor (i = 0; i < ctx.dpb_frames_nb; i++) {\n+\t\tret = tegra_vde_copy_and_validate_frame(dev, &frame, vaddr);\n+\t\tif (ret)\n+\t\t\tgoto cleanup;\n+\n+\t\tdpb_frames[i].flags = frame.flags;\n+\t\tdpb_frames[i].frame_num = frame.frame_num;\n+\n+\t\tdma_dir = (i == 0) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;\n+\n+\t\tret = tegra_vde_attach_frame_dmabufs(dev,\n+\t\t\t\t\t\t     &dpb_frames[i], &frame,\n+\t\t\t\t\t\t     dma_dir,\n+\t\t\t\t\t\t     ctx.is_baseline_profile,\n+\t\t\t\t\t\t     macroblocks_nb * 64);\n+\t\tif (ret) {\n+\t\t\ttegra_vde_deattach_frame_dmabufs(&dpb_frames[i]);\n+\t\t\tgoto cleanup;\n+\t\t}\n+\n+\t\tvaddr += sizeof(frame);\n+\t}\n+\n+\tret = clk_prepare_enable(vde->clk);\n+\tif (ret) {\n+\t\tdev_err(dev, \"Failed to enable clk: %d\\n\", ret);\n+\t\tgoto cleanup;\n+\t}\n+\n+\tret = mutex_lock_interruptible(&vde->lock);\n+\tif (ret)\n+\t\tgoto clkgate;\n+\n+\tret = reset_control_deassert(vde->rst);\n+\tif (ret) {\n+\t\tdev_err(dev, \"Failed to deassert reset: %d\\n\", ret);\n+\t\tclk_disable_unprepare(vde->clk);\n+\t\tgoto unlock;\n+\t}\n+\n+\tret = tegra_vde_setup_context(vde, &ctx, dpb_frames,\n+\t\t\t\t      bitstream_data_paddr,\n+\t\t\t\t      bitstream_data_size,\n+\t\t\t\t      macroblocks_nb);\n+\tif (ret)\n+\t\tgoto reset;\n+\n+\ttegra_vde_decode_frame(vde, macroblocks_nb);\n+\n+\ttimeout = !wait_for_completion_io_timeout(&vde->decode_completion,\n+\t\t\t\t\t\t  TEGRA_VDE_TIMEOUT);\n+\tif (timeout) {\n+\t\tbsev_paddr = readl(vde->regs + BSEV(0x10));\n+\t\tmacroblocks_nb = readl(vde->regs + SXE(0xC8)) & 0x1FFF;\n+\n+\t\tdev_err(dev, \"Decoding failed, \"\n+\t\t\t\t\"read 0x%X bytes : %u macroblocks parsed\\n\",\n+\t\t\tbsev_paddr ? bsev_paddr - bitstream_data_paddr : 0,\n+\t\t\tmacroblocks_nb);\n+\t}\n+\n+reset:\n+\t/*\n+\t * We rely on the VDE registers reset value, otherwise VDE would\n+\t * cause bus lockup.\n+\t */\n+\tret = reset_control_assert(vde->rst);\n+\tif (ret)\n+\t\tdev_err(dev, \"Failed to assert reset: %d\\n\", ret);\n+\n+\tif (timeout)\n+\t\tret = -EIO;\n+\n+unlock:\n+\tmutex_unlock(&vde->lock);\n+\n+clkgate:\n+\tclk_disable_unprepare(vde->clk);\n+\n+cleanup:\n+\tif (dpb_frames)\n+\t\twhile (i--)\n+\t\t\ttegra_vde_deattach_frame_dmabufs(&dpb_frames[i]);\n+\n+\tkfree(dpb_frames);\n+\n+\ttegra_vde_detach_and_put_dmabuf(bitstream_data_dmabuf_attachment);\n+\n+\treturn ret;\n+}\n+\n+static long tegra_vde_unlocked_ioctl(struct file *filp,\n+\t\t\t\t     unsigned int cmd, unsigned long arg)\n+{\n+\tstruct miscdevice *miscdev = filp->private_data;\n+\tstruct tegra_vde *vde = container_of(miscdev, struct tegra_vde,\n+\t\t\t\t\t     miscdev);\n+\n+\tswitch (cmd) {\n+\tcase TEGRA_VDE_IOCTL_DECODE_H264:\n+\t\treturn tegra_vde_ioctl_decode_h264(vde, arg);\n+\t}\n+\n+\tdev_err(miscdev->parent, \"Invalid IOCTL command %u\\n\", cmd);\n+\n+\treturn -ENOTTY;\n+}\n+\n+static const struct file_operations tegra_vde_fops = {\n+\t.owner\t\t= THIS_MODULE,\n+\t.unlocked_ioctl\t= tegra_vde_unlocked_ioctl,\n+};\n+\n+static irqreturn_t tegra_vde_isr(int irq, void *data)\n+{\n+\tstruct tegra_vde *vde = data;\n+\n+\ttegra_vde_set_bits(vde->regs, 0, FRAMEID(0x208));\n+\tcomplete(&vde->decode_completion);\n+\n+\treturn IRQ_HANDLED;\n+}\n+\n+static int tegra_vde_probe(struct platform_device *pdev)\n+{\n+\tstruct resource *res_regs, *res_iram;\n+\tstruct device *dev = &pdev->dev;\n+\tstruct tegra_vde *vde;\n+\tint ret;\n+\n+\tvde = devm_kzalloc(&pdev->dev, sizeof(*vde), GFP_KERNEL);\n+\tif (!vde)\n+\t\treturn -ENOMEM;\n+\n+\tplatform_set_drvdata(pdev, vde);\n+\n+\tres_regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, \"regs\");\n+\tif (!res_regs)\n+\t\treturn -ENODEV;\n+\n+\tres_iram = platform_get_resource_byname(pdev, IORESOURCE_MEM, \"iram\");\n+\tif (!res_iram)\n+\t\treturn -ENODEV;\n+\n+\tvde->irq = platform_get_irq_byname(pdev, \"sync-token\");\n+\tif (vde->irq < 0)\n+\t\treturn vde->irq;\n+\n+\tvde->regs = devm_ioremap_resource(dev, res_regs);\n+\tif (IS_ERR(vde->regs))\n+\t\treturn PTR_ERR(vde->regs);\n+\n+\tvde->iram = devm_ioremap_resource(dev, res_iram);\n+\tif (IS_ERR(vde->iram))\n+\t\treturn PTR_ERR(vde->iram);\n+\n+\tvde->clk = devm_clk_get(dev, NULL);\n+\tif (IS_ERR(vde->clk)) {\n+\t\tdev_err(dev, \"Could not get VDE clk\\n\");\n+\t\treturn PTR_ERR(vde->clk);\n+\t}\n+\n+\tvde->rst = devm_reset_control_get(dev, \"vde\");\n+\tif (IS_ERR(vde->rst)) {\n+\t\tdev_err(dev, \"Could not get VDE reset\\n\");\n+\t\treturn PTR_ERR(vde->rst);\n+\t}\n+\n+\tret = devm_request_irq(dev, vde->irq, tegra_vde_isr, IRQF_SHARED,\n+\t\t\t       dev_name(dev), vde);\n+\tif (ret)\n+\t\treturn -ENODEV;\n+\n+\tret = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_VDEC,\n+\t\t\t\t\t\tvde->clk, vde->rst);\n+\tif (ret) {\n+\t\tdev_err(&pdev->dev, \"Failed to power up VDE unit\\n\");\n+\t\treturn ret;\n+\t}\n+\n+\tret = reset_control_assert(vde->rst);\n+\tif (ret) {\n+\t\tdev_err(dev, \"Failed to assert reset: %d\\n\", ret);\n+\t\treturn ret;\n+\t}\n+\n+\tclk_disable_unprepare(vde->clk);\n+\n+\tmutex_init(&vde->lock);\n+\tinit_completion(&vde->decode_completion);\n+\n+\tvde->iram_lists_paddr = res_iram->start;\n+\tvde->miscdev.minor = MISC_DYNAMIC_MINOR;\n+\tvde->miscdev.name = \"tegra_vde\";\n+\tvde->miscdev.fops = &tegra_vde_fops;\n+\tvde->miscdev.parent = dev;\n+\n+\tret = misc_register(&vde->miscdev);\n+\tif (ret)\n+\t\treturn -ENODEV;\n+\n+\treturn 0;\n+}\n+\n+static int tegra_vde_remove(struct platform_device *pdev)\n+{\n+\tstruct tegra_vde *vde = platform_get_drvdata(pdev);\n+\n+\tmisc_deregister(&vde->miscdev);\n+\n+\treturn 0;\n+}\n+\n+static const struct of_device_id tegra_vde_of_match[] = {\n+\t{ .compatible = \"nvidia,tegra20-vde\", },\n+\t{ },\n+};\n+MODULE_DEVICE_TABLE(of, tegra_vde_of_match);\n+\n+static struct platform_driver tegra_vde_driver = {\n+\t.probe\t\t= tegra_vde_probe,\n+\t.remove\t\t= tegra_vde_remove,\n+\t.driver\t\t= {\n+\t\t.name\t\t= \"tegra-vde\",\n+\t\t.of_match_table = tegra_vde_of_match,\n+\t},\n+};\n+module_platform_driver(tegra_vde_driver);\n+\n+MODULE_DESCRIPTION(\"NVIDIA Tegra20 Video Decoder driver\");\n+MODULE_AUTHOR(\"Dmitry Osipenko\");\n+MODULE_LICENSE(\"GPL\");\n","prefixes":["v1","1/2"]}