From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753249AbcCUJmY (ORCPT ); Mon, 21 Mar 2016 05:42:24 -0400 Received: from lucky1.263xmail.com ([211.157.147.133]:60952 "EHLO lucky1.263xmail.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751696AbcCUJmS (ORCPT ); Mon, 21 Mar 2016 05:42:18 -0400 X-263anti-spam: KSV:0; X-MAIL-GRAY: 1 X-MAIL-DELIVERY: 0 X-KSVirus-check: 0 X-ABS-CHECKED: 4 X-ADDR-CHECKED: 0 X-RL-SENDER: ykk@rock-chips.com X-FST-TO: airlied@linux.ie X-SENDER-IP: 58.22.7.114 X-LOGIN-NAME: ykk@rock-chips.com X-UNIQUE-TAG: <5498ed0ad72037adff61a7a3668c0343> X-ATTACHMENT-NUM: 0 X-DNS-TYPE: 0 From: Yakir Yang To: David Airlie , Mark Yao , Heiko Stuebner Cc: Joonyoung Shim , Kumar Gala , Ian Campbell , Rob Herring , Pawel Moll , Russell King , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-rockchip@lists.infradead.org, linux-arm-kernel@lists.infradead.org, Yakir Yang Subject: [RFC PATCH v1 2/4] drm: rockchip: add RGA driver support Date: Mon, 21 Mar 2016 17:40:06 +0800 Message-Id: <1458553206-26880-1-git-send-email-ykk@rock-chips.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1458552518-25527-1-git-send-email-ykk@rock-chips.com> References: <1458552518-25527-1-git-send-email-ykk@rock-chips.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Rockchip RGA is a separate 2D raster graphic acceleration unit. It accelerates 2D graphics operations, such as point/line drawing, image scaling, rotation, BitBLT, alpha blending and image blur/sharpness. The RGA driver is based on Exynos G2D driver, it is performed by two tasks simply. 1. Configures the rendering parameters, such as foreground color and coordinates data by setting the drawing context registers. 2. Start the rendering process by calling rga_exec() ioctl. The RGA supports DMA mode as host interface. User can make command list to reduce HOST(ARM) loads. The contents of The command list is setted to relevant registers of RGA by DMA. The command list is composed Header and command sets and Tail. - Header: The number of command set(4Bytes) - Command set: Register offset(4Bytes) + Register data(4Bytes) - Tail: Pointer of base address of the other command list(4Bytes) By Tail field, the G2D can process many command lists without halt at one go. The G2D has following the rendering pipeline. ---> Color Fill ---> | | --> DMA (read) ---> Src Bitmap Process ----> Alpha/ROP ---> Format convert ---> DMA (Write) | | ---> Dst Bitmap Process ---> And supports various operations from the rendering pipeline. - copy - fast solid color fill - rotation - flip - 4 operand raster operation(ROP4) - alpha blending - color key - dithering - etc User should make the command list to data and registers needed by operation to use. The Rockchip RGA driver only manages the command lists received from user. Some registers needs memory base address(physical address) of image. User doesn't know its physical address, so fills the gem handle of that memory than address to command sets, then RGA driver converts it to memory base address. We adds three ioctls for Rockchip RGA. - ioctls DRM_ROCKCHIP_RGA_GET_VER: get the RGA hardware version DRM_ROCKCHIP_RGA_SET_CMDLIST: set the command list from user to driver DRM_ROCKCHIP_RGA_EXEC: execute the command lists setted to driver Signed-off-by: Yakir Yang --- .../bindings/display/rockchip/rockchip-rga.txt | 36 + drivers/gpu/drm/rockchip/Kconfig | 9 + drivers/gpu/drm/rockchip/Makefile | 1 + drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 35 +- drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 4 + drivers/gpu/drm/rockchip/rockchip_drm_rga.c | 977 +++++++++++++++++++++ drivers/gpu/drm/rockchip/rockchip_drm_rga.h | 108 +++ include/uapi/drm/rockchip_drm.h | 63 ++ 8 files changed, 1232 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/display/rockchip/rockchip-rga.txt create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_rga.c create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_rga.h create mode 100644 include/uapi/drm/rockchip_drm.h diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-rga.txt b/Documentation/devicetree/bindings/display/rockchip/rockchip-rga.txt new file mode 100644 index 0000000..0c606cb --- /dev/null +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-rga.txt @@ -0,0 +1,36 @@ +device-tree bindings for rockchip 2D raster graphic acceleration controller (RGA) + +RGA is a separate 2D raster graphic acceleration unit. It accelerates 2D +graphics operations, such as point/line drawing, image scaling, rotation, +BitBLT, alpha blending and image blur/sharpness. + +Required properties: +- compatible: value should be one of the following + "rockchip,rk3228-rga"; + "rockchip,rk3288-rga"; + "rockchip,rk3399-rga"; + +- interrupts: RGA interrupt number. + +- clocks: phandle to RGA sclk/hclk/aclk clocks + +- clock-names: should be "aclk" "hclk" and "sclk" + +- resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names: should be "aclk" "hclk" and "sclk" + +Example: +SoC specific DT entry: + rga: rga@ff680000 { + compatible = "rockchip,rk3399-rga"; + reg = <0xff680000 0x10000>; + interrupts = ; + interrupt-names = "rga"; + clocks = <&cru ACLK_RGA>, <&cru HCLK_RGA>, <&cru SCLK_RGA>; + clock-names = "aclk", "hclk", "sclk"; + + resets = <&cru SRST_A_RGA>, <&cru SRST_H_RGA>, <&cru SRST_RGA_CORE>; + reset-names = "aclk", "hclk", "sclk"; + status = "disabled"; + }; diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index 76b3362..220221b 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -16,6 +16,15 @@ config DRM_ROCKCHIP 2D or 3D acceleration; acceleration is performed by other IP found on the SoC. +config ROCKCHIP_DRM_RGA + tristate "Rockchip RGA support" + depends on DRM_ROCKCHIP + help + Choose this option to enable support for Rockchip RGA. + Rockchip RGA is a kind of hardware 2D accelerator, and it support + solid roration, scaling, color format transform, say Y to enable its + driver + config ROCKCHIP_DW_HDMI tristate "Rockchip specific extensions for Synopsys DW HDMI" depends on DRM_ROCKCHIP diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index df8fbef..7de547c 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -9,5 +9,6 @@ rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o obj-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o obj-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o obj-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o +obj-$(CONFIG_ROCKCHIP_DRM_RGA) += rockchip_drm_rga.o obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o rockchip_vop_reg.o diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index 4e0feb2..1638bc9 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -25,10 +25,13 @@ #include #include +#include + #include "rockchip_drm_drv.h" #include "rockchip_drm_fb.h" #include "rockchip_drm_fbdev.h" #include "rockchip_drm_gem.h" +#include "rockchip_drm_rga.h" #define DRIVER_NAME "rockchip" #define DRIVER_DESC "RockChip Soc DRM" @@ -277,16 +280,28 @@ EXPORT_SYMBOL_GPL(rockchip_unregister_subdrv); static int rockchip_drm_open(struct drm_device *dev, struct drm_file *file) { + struct rockchip_drm_file_private *file_priv; struct drm_rockchip_subdrv *subdrv; int ret = 0; + file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL); + if (!file_priv) + return -ENOMEM; + + file->driver_priv = file_priv; + list_for_each_entry(subdrv, &rockchip_drm_subdrv_list, list) { ret = subdrv->open(dev, subdrv->dev, file); if (ret) - return ret; + goto err_file_priv_free; } return 0; + +err_file_priv_free: + kfree(file_priv); + file->driver_priv = NULL; + return ret; } static void rockchip_drm_preclose(struct drm_device *dev, @@ -298,6 +313,12 @@ static void rockchip_drm_preclose(struct drm_device *dev, subdrv->close(dev, subdrv->dev, file); } +static void rockchip_drm_postclose(struct drm_device *dev, + struct drm_file *file) +{ + kfree(file->driver_priv); +} + void rockchip_drm_lastclose(struct drm_device *dev) { struct rockchip_drm_private *priv = dev->dev_private; @@ -305,6 +326,15 @@ void rockchip_drm_lastclose(struct drm_device *dev) drm_fb_helper_restore_fbdev_mode_unlocked(&priv->fbdev_helper); } +static const struct drm_ioctl_desc rockchip_ioctls[] = { + DRM_IOCTL_DEF_DRV(ROCKCHIP_RGA_GET_VER, rockchip_rga_get_ver_ioctl, + DRM_AUTH | DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(ROCKCHIP_RGA_SET_CMDLIST, rockchip_rga_set_cmdlist_ioctl, + DRM_AUTH | DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(ROCKCHIP_RGA_EXEC, rockchip_rga_exec_ioctl, + DRM_AUTH | DRM_RENDER_ALLOW), +}; + static const struct file_operations rockchip_drm_driver_fops = { .owner = THIS_MODULE, .open = drm_open, @@ -330,6 +360,7 @@ static struct drm_driver rockchip_drm_driver = { .unload = rockchip_drm_unload, .open = rockchip_drm_open, .preclose = rockchip_drm_preclose, + .postclose = rockchip_drm_postclose, .lastclose = rockchip_drm_lastclose, .get_vblank_counter = drm_vblank_no_hw_counter, .enable_vblank = rockchip_drm_crtc_enable_vblank, @@ -347,6 +378,8 @@ static struct drm_driver rockchip_drm_driver = { .gem_prime_vmap = rockchip_gem_prime_vmap, .gem_prime_vunmap = rockchip_gem_prime_vunmap, .gem_prime_mmap = rockchip_gem_mmap_buf, + .ioctls = rockchip_ioctls, + .num_ioctls = ARRAY_SIZE(rockchip_ioctls), .fops = &rockchip_drm_driver_fops, .name = DRIVER_NAME, .desc = DRIVER_DESC, diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index 5ea5fcb..ea30ba6 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -53,6 +53,10 @@ struct drm_rockchip_subdrv { struct drm_file *file); }; +struct rockchip_drm_file_private { + struct rockchip_drm_rga_private *rga_priv; +}; + struct rockchip_atomic_commit { struct work_struct work; struct drm_atomic_state *state; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_rga.c b/drivers/gpu/drm/rockchip/rockchip_drm_rga.c new file mode 100644 index 0000000..4202121 --- /dev/null +++ b/drivers/gpu/drm/rockchip/rockchip_drm_rga.c @@ -0,0 +1,977 @@ +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: Yakir Yang + * + * based on exynos_drm_g2d.c + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "rockchip_drm_drv.h" +#include "rockchip_drm_rga.h" + +#define RGA_MODE_BASE_REG 0x0100 +#define RGA_MODE_MAX_REG 0x017C + +#define RGA_SYS_CTRL 0x0000 +#define RGA_CMD_CTRL 0x0004 +#define RGA_CMD_BASE 0x0008 +#define RGA_INT 0x0010 +#define RGA_MMU_CTRL0 0x0014 +#define RGA_VERSION_INFO 0x0028 + +#define RGA_SRC_Y_RGB_BASE_ADDR 0x0108 +#define RGA_SRC_CB_BASE_ADDR 0x010C +#define RGA_SRC_CR_BASE_ADDR 0x0110 +#define RGA_SRC1_RGB_BASE_ADDR 0x0114 +#define RGA_DST_Y_RGB_BASE_ADDR 0x013C +#define RGA_DST_CB_BASE_ADDR 0x0140 +#define RGA_DST_CR_BASE_ADDR 0x014C +#define RGA_MMU_CTRL1 0x016C +#define RGA_MMU_SRC_BASE 0x0170 +#define RGA_MMU_SRC1_BASE 0x0174 +#define RGA_MMU_DST_BASE 0x0178 + +static void rga_dma_flush_range(void *ptr, int size) +{ +#ifdef CONFIG_ARM + dmac_flush_range(ptr, ptr + size); + outer_flush_range(virt_to_phys(ptr), virt_to_phys(ptr + size)); +#elif CONFIG_ARM64 + __dma_flush_range(ptr, ptr + size); +#endif +} + +static inline void rga_write(struct rockchip_rga *rga, u32 reg, u32 value) +{ + writel(value, rga->regs + reg); +} + +static inline u32 rga_read(struct rockchip_rga *rga, u32 reg) +{ + return readl(rga->regs + reg); +} + +static inline void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask) +{ + u32 temp = rga_read(rga, reg) & ~(mask); + + temp |= val & mask; + rga_write(rga, reg, temp); +} + +static int rga_enable_clocks(struct rockchip_rga *rga) +{ + int ret; + + ret = clk_prepare_enable(rga->sclk); + if (ret) { + dev_err(rga->dev, "Cannot enable rga sclk: %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(rga->aclk); + if (ret) { + dev_err(rga->dev, "Cannot enable rga aclk: %d\n", ret); + goto err_disable_sclk; + } + + ret = clk_prepare_enable(rga->hclk); + if (ret) { + dev_err(rga->dev, "Cannot enable rga hclk: %d\n", ret); + goto err_disable_aclk; + } + + return 0; + +err_disable_sclk: + clk_disable_unprepare(rga->sclk); +err_disable_aclk: + clk_disable_unprepare(rga->aclk); + + return ret; +} + +static void rga_disable_clocks(struct rockchip_rga *rga) +{ + clk_disable_unprepare(rga->sclk); + clk_disable_unprepare(rga->hclk); + clk_disable_unprepare(rga->aclk); +} + +static void rga_init_cmdlist(struct rockchip_rga *rga) +{ + struct rga_cmdlist_node *node; + int nr; + + node = rga->cmdlist_node; + + for (nr = 0; nr < ARRAY_SIZE(rga->cmdlist_node); nr++) + list_add_tail(&node[nr].list, &rga->free_cmdlist); +} + +static int rga_alloc_dma_buf_for_cmdlist(struct rga_runqueue_node *runqueue) +{ + struct list_head *run_cmdlist = &runqueue->run_cmdlist; + struct device *dev = runqueue->dev; + struct dma_attrs cmdlist_dma_attrs; + struct rga_cmdlist_node *node; + void *cmdlist_pool_virt; + dma_addr_t cmdlist_pool; + int cmdlist_cnt = 0; + int count = 0; + + list_for_each_entry(node, run_cmdlist, list) + cmdlist_cnt++; + + init_dma_attrs(&cmdlist_dma_attrs); + dma_set_attr(DMA_ATTR_WRITE_COMBINE, &runqueue->cmdlist_dma_attrs); + + cmdlist_pool_virt = dma_alloc_attrs(dev, cmdlist_cnt * RGA_CMDLIST_SIZE, + &cmdlist_pool, GFP_KERNEL, + &cmdlist_dma_attrs); + if (!cmdlist_pool_virt) { + dev_err(dev, "failed to allocate cmdlist dma memory\n"); + return -ENOMEM; + } + + /* + * Fill in the RGA operation registers from cmdlist command buffer, + * and also filled in the MMU TLB base information. + */ + list_for_each_entry(node, run_cmdlist, list) { + struct rga_cmdlist *cmdlist = &node->cmdlist; + unsigned int mmu_ctrl = 0; + unsigned int *dest; + unsigned int reg; + int i; + + dest = cmdlist_pool_virt + RGA_CMDLIST_SIZE * 4 * count++; + + for (i = 0; i < cmdlist->last / 2; i++) { + reg = (node->cmdlist.data[2 * i] - RGA_MODE_BASE_REG); + if (reg > RGA_MODE_BASE_REG) + continue; + dest[reg << 2] = cmdlist->data[2 * i + 1]; + } + + if (cmdlist->src_mmu_pages) { + reg = RGA_MMU_SRC_BASE - RGA_MODE_BASE_REG; + dest[reg << 2] = virt_to_phys(cmdlist->src_mmu_pages) >> 4; + mmu_ctrl |= 0x7; + } + + if (cmdlist->dst_mmu_pages) { + reg = RGA_MMU_DST_BASE - RGA_MODE_BASE_REG; + dest[reg << 2] = virt_to_phys(cmdlist->dst_mmu_pages) >> 4; + mmu_ctrl |= 0x7 << 8; + } + + if (cmdlist->src1_mmu_pages) { + reg = RGA_MMU_SRC1_BASE - RGA_MODE_BASE_REG; + dest[reg << 2] = virt_to_phys(cmdlist->src1_mmu_pages) >> 4; + mmu_ctrl |= 0x7 << 4; + } + + reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG; + dest[reg << 2] = mmu_ctrl; + } + + rga_dma_flush_range(cmdlist_pool_virt, cmdlist_cnt * RGA_CMDLIST_SIZE); + + runqueue->cmdlist_dma_attrs = cmdlist_dma_attrs; + runqueue->cmdlist_pool_virt = cmdlist_pool_virt; + runqueue->cmdlist_pool = cmdlist_pool; + runqueue->cmdlist_cnt = cmdlist_cnt; + + return 0; +} + +static int rga_check_reg_offset(struct device *dev, + struct rga_cmdlist_node *node) +{ + struct rga_cmdlist *cmdlist = &node->cmdlist; + int index; + int reg; + int i; + + for (i = 0; i < cmdlist->last / 2; i++) { + index = cmdlist->last - 2 * (i + 1); + reg = cmdlist->data[index]; + + switch (reg) { + case RGA_BUF_TYPE_GEMFD | RGA_DST_Y_RGB_BASE_ADDR: + case RGA_BUF_TYPE_GEMFD | RGA_SRC_Y_RGB_BASE_ADDR: + break; + + case RGA_BUF_TYPE_USERPTR | RGA_DST_Y_RGB_BASE_ADDR: + case RGA_BUF_TYPE_USERPTR | RGA_SRC_Y_RGB_BASE_ADDR: + goto err; + + default: + if (reg < RGA_MODE_BASE_REG || reg > RGA_MODE_MAX_REG) + goto err; + + if (reg % 4) + goto err; + } + } + + return 0; + +err: + dev_err(dev, "Bad register offset: 0x%lx\n", cmdlist->data[index]); + return -EINVAL; +} + +static struct dma_buf_attachment * +rga_gem_buf_to_pages(struct rockchip_rga *rga, void **mmu_pages, int fd) +{ + struct dma_buf_attachment *attach; + struct dma_buf *dmabuf; + struct sg_table *sgt; + struct scatterlist *sgl; + unsigned int mapped_size = 0; + unsigned int address; + unsigned int len; + unsigned int i, p; + unsigned int *pages; + int ret; + + dmabuf = dma_buf_get(fd); + if (IS_ERR(dmabuf)) { + dev_err(rga->dev, "Failed to get dma_buf with fd %d\n", fd); + return ERR_PTR(-EINVAL); + } + + attach = dma_buf_attach(dmabuf, rga->dev); + if (IS_ERR(attach)) { + dev_err(rga->dev, "Failed to attach dma_buf\n"); + ret = PTR_ERR(attach); + goto failed_attach; + } + + sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); + if (IS_ERR(sgt)) { + dev_err(rga->dev, "Failed to map dma_buf attachment\n"); + ret = PTR_ERR(sgt); + goto failed_detach; + } + + /* + * Alloc (2^3 * 4K) = 32K byte for storing pages, those space could + * cover 32K * 4K = 128M ram address. + */ + pages = (unsigned int *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 3); + + for_each_sg(sgt->sgl, sgl, sgt->nents, i) { + len = sg_dma_len(sgl) >> PAGE_SHIFT; + address = sg_phys(sgl); + + for (p = 0; p < len; p++) { + dma_addr_t phys = address + (p << PAGE_SHIFT); + void *virt = phys_to_virt(phys); + + rga_dma_flush_range(virt, 4 * 1024); + pages[mapped_size + p] = phys; + } + + mapped_size += len; + } + + rga_dma_flush_range(pages, 32 * 1024); + + *mmu_pages = pages; + + dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL); + + return attach; + +failed_detach: + dma_buf_detach(dmabuf, attach); +failed_attach: + dma_buf_put(dmabuf); + + return ERR_PTR(ret); +} + +static int rga_map_cmdlist_gem(struct rockchip_rga *rga, + struct rga_cmdlist_node *node, + struct drm_device *drm_dev, + struct drm_file *file) +{ + struct rga_cmdlist *cmdlist = &node->cmdlist; + struct dma_buf_attachment *attach; + void *mmu_pages; + int fd; + int i; + + for (i = 0; i < cmdlist->last / 2; i++) { + int index = cmdlist->last - 2 * (i + 1); + + switch (cmdlist->data[index]) { + case RGA_SRC_Y_RGB_BASE_ADDR | RGA_BUF_TYPE_GEMFD: + fd = cmdlist->data[index + 1]; + attach = rga_gem_buf_to_pages(rga, &mmu_pages, fd); + + cmdlist->src_attach = attach; + cmdlist->src_mmu_pages = mmu_pages; + break; + + case RGA_DST_Y_RGB_BASE_ADDR | RGA_BUF_TYPE_GEMFD: + fd = cmdlist->data[index + 1]; + attach = rga_gem_buf_to_pages(rga, &mmu_pages, fd); + + cmdlist->dst_attach = attach; + cmdlist->dst_mmu_pages = mmu_pages; + break; + } + } + + return 0; +} + +static void rga_unmap_cmdlist_gem(struct rockchip_rga *rga, + struct rga_cmdlist_node *node) +{ + struct dma_buf_attachment *attach; + struct dma_buf *dma_buf; + + attach = node->cmdlist.src_attach; + if (attach) { + dma_buf = attach->dmabuf; + dma_buf_detach(dma_buf, attach); + dma_buf_put(dma_buf); + } + node->cmdlist.src_attach = NULL; + + attach = node->cmdlist.dst_attach; + if (attach) { + dma_buf = attach->dmabuf; + dma_buf_detach(dma_buf, attach); + dma_buf_put(dma_buf); + } + node->cmdlist.dst_attach = NULL; + + if (node->cmdlist.src_mmu_pages) + free_pages((unsigned long)node->cmdlist.src_mmu_pages, 3); + node->cmdlist.src_mmu_pages = NULL; + + if (node->cmdlist.src1_mmu_pages) + free_pages((unsigned long)node->cmdlist.src1_mmu_pages, 3); + node->cmdlist.src1_mmu_pages = NULL; + + if (node->cmdlist.dst_mmu_pages) + free_pages((unsigned long)node->cmdlist.dst_mmu_pages, 3); + node->cmdlist.dst_mmu_pages = NULL; +} + +static void rga_cmd_start(struct rockchip_rga *rga, + struct rga_runqueue_node *runqueue) +{ + int ret; + + ret = pm_runtime_get_sync(rga->dev); + if (ret < 0) + return; + + rga_write(rga, RGA_SYS_CTRL, 0x00); + + rga_write(rga, RGA_CMD_BASE, runqueue->cmdlist_pool); + + rga_write(rga, RGA_SYS_CTRL, 0x22); + + rga_write(rga, RGA_INT, 0x600); + + rga_write(rga, RGA_CMD_CTRL, ((runqueue->cmdlist_cnt - 1) << 3) | 0x1); +} + +static void rga_free_runqueue_node(struct rockchip_rga *rga, + struct rga_runqueue_node *runqueue) +{ + struct rga_cmdlist_node *node; + + if (!runqueue) + return; + + if (runqueue->cmdlist_pool_virt && runqueue->cmdlist_pool) + dma_free_attrs(rga->dev, runqueue->cmdlist_cnt * RGA_CMDLIST_SIZE, + runqueue->cmdlist_pool_virt, + runqueue->cmdlist_pool, + &runqueue->cmdlist_dma_attrs); + + mutex_lock(&rga->cmdlist_mutex); + /* + * commands in run_cmdlist have been completed so unmap all gem + * objects in each command node so that they are unreferenced. + */ + list_for_each_entry(node, &runqueue->run_cmdlist, list) + rga_unmap_cmdlist_gem(rga, node); + list_splice_tail_init(&runqueue->run_cmdlist, &rga->free_cmdlist); + mutex_unlock(&rga->cmdlist_mutex); + + kmem_cache_free(rga->runqueue_slab, runqueue); +} + +static struct rga_runqueue_node *rga_get_runqueue(struct rockchip_rga *rga) +{ + struct rga_runqueue_node *runqueue; + + if (list_empty(&rga->runqueue_list)) + return NULL; + + runqueue = list_first_entry(&rga->runqueue_list, + struct rga_runqueue_node, list); + list_del_init(&runqueue->list); + + return runqueue; +} + +static void rga_exec_runqueue(struct rockchip_rga *rga) +{ + rga->runqueue_node = rga_get_runqueue(rga); + if (rga->runqueue_node) + rga_cmd_start(rga, rga->runqueue_node); +} + +static struct rga_cmdlist_node *rga_get_cmdlist(struct rockchip_rga *rga) +{ + struct rga_cmdlist_node *node; + struct device *dev = rga->dev; + + mutex_lock(&rga->cmdlist_mutex); + if (list_empty(&rga->free_cmdlist)) { + dev_err(dev, "there is no free cmdlist\n"); + mutex_unlock(&rga->cmdlist_mutex); + return NULL; + } + + node = list_first_entry(&rga->free_cmdlist, + struct rga_cmdlist_node, list); + list_del_init(&node->list); + mutex_unlock(&rga->cmdlist_mutex); + + return node; +} + +static void rga_add_cmdlist_to_inuse(struct rockchip_drm_rga_private *rga_priv, + struct rga_cmdlist_node *node) +{ + struct rga_cmdlist_node *lnode; + + if (list_empty(&rga_priv->inuse_cmdlist)) + goto add_to_list; + + /* this links to base address of new cmdlist */ + lnode = list_entry(rga_priv->inuse_cmdlist.prev, + struct rga_cmdlist_node, list); + +add_to_list: + list_add_tail(&node->list, &rga_priv->inuse_cmdlist); +} + +/* + * IOCRL functions for userspace to get RGA version. + */ +int rockchip_rga_get_ver_ioctl(struct drm_device *drm_dev, void *data, + struct drm_file *file) +{ + struct rockchip_drm_file_private *file_priv = file->driver_priv; + struct rockchip_drm_rga_private *rga_priv = file_priv->rga_priv; + struct drm_rockchip_rga_get_ver *ver = data; + struct rockchip_rga *rga; + struct device *dev; + + if (!rga_priv) + return -ENODEV; + + dev = rga_priv->dev; + if (!dev) + return -ENODEV; + + rga = dev_get_drvdata(dev); + if (!rga) + return -EFAULT; + + ver->major = rga->version.major; + ver->minor = rga->version.minor; + + return 0; +} + +/* + * IOCRL functions for userspace to send an RGA request. + */ +int rockchip_rga_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data, + struct drm_file *file) +{ + struct rockchip_drm_file_private *file_priv = file->driver_priv; + struct rockchip_drm_rga_private *rga_priv = file_priv->rga_priv; + struct drm_rockchip_rga_set_cmdlist *req = data; + struct rga_cmdlist_node *node; + struct rga_cmdlist *cmdlist; + struct rockchip_rga *rga; + int ret; + + if (!rga_priv) + return -ENODEV; + + if (!rga_priv->dev) + return -ENODEV; + + rga = dev_get_drvdata(rga_priv->dev); + if (!rga) + return -EFAULT; + + node = rga_get_cmdlist(rga); + if (!node) + return -ENOMEM; + + cmdlist = &node->cmdlist; + cmdlist->last = 0; + + if (req->cmd_nr > RGA_CMDLIST_SIZE || req->cmd_buf_nr > RGA_CMDBUF_SIZE) { + dev_err(rga->dev, "cmdlist size is too big\n"); + return -EINVAL; + } + + /* + * Copy the command / buffer registers setting from userspace, each + * command have two integer, one for register offset, another for + * register value. + */ + if (copy_from_user((void *)cmdlist->data, (const void __user *)req->cmd, + sizeof(struct drm_rockchip_rga_cmd) * req->cmd_nr)) + return -EFAULT; + cmdlist->last += req->cmd_nr * 2; + + if (copy_from_user((void *)cmdlist->data + cmdlist->last, + (const void __user *)req->cmd_buf, + sizeof(struct drm_rockchip_rga_cmd) * req->cmd_buf_nr)) + return -EFAULT; + cmdlist->last += req->cmd_buf_nr * 2; + + /* + * Check the userspace command registers, and mapping the framebuffer, + * create the RGA mmu pages or get the framebuffer dma address. + */ + ret = rga_check_reg_offset(rga->dev, node); + if (ret < 0) + return ret; + + ret = rga_map_cmdlist_gem(rga, node, drm_dev, file); + if (ret < 0) + return ret; + + rga_add_cmdlist_to_inuse(rga_priv, node); + + return 0; +} + +/* + * IOCRL functions for userspace to start RGA transform. + */ +int rockchip_rga_exec_ioctl(struct drm_device *drm_dev, void *data, + struct drm_file *file) +{ + struct rockchip_drm_file_private *file_priv = file->driver_priv; + struct rockchip_drm_rga_private *rga_priv = file_priv->rga_priv; + struct rga_runqueue_node *runqueue; + struct rockchip_rga *rga; + struct device *dev; + int ret; + + if (!rga_priv) + return -ENODEV; + + dev = rga_priv->dev; + if (!dev) + return -ENODEV; + + rga = dev_get_drvdata(dev); + if (!rga) + return -EFAULT; + + runqueue = kmem_cache_alloc(rga->runqueue_slab, GFP_KERNEL); + if (!runqueue) { + dev_err(rga->dev, "failed to allocate memory\n"); + return -ENOMEM; + } + + runqueue->dev = rga->dev; + + init_completion(&runqueue->complete); + + INIT_LIST_HEAD(&runqueue->run_cmdlist); + + list_splice_init(&rga_priv->inuse_cmdlist, &runqueue->run_cmdlist); + + if (list_empty(&runqueue->run_cmdlist)) { + dev_err(rga->dev, "there is no inuse cmdlist\n"); + kmem_cache_free(rga->runqueue_slab, runqueue); + return -EPERM; + } + + ret = rga_alloc_dma_buf_for_cmdlist(runqueue); + if (ret < 0) { + dev_err(rga->dev, "cmdlist init failed\n"); + return ret; + } + + mutex_lock(&rga->runqueue_mutex); + runqueue->pid = current->pid; + runqueue->file = file; + list_add_tail(&runqueue->list, &rga->runqueue_list); + if (!rga->runqueue_node) + rga_exec_runqueue(rga); + mutex_unlock(&rga->runqueue_mutex); + + wait_for_completion(&runqueue->complete); + rga_free_runqueue_node(rga, runqueue); + + return 0; +} + +static int rockchip_rga_open(struct drm_device *drm_dev, struct device *dev, + struct drm_file *file) +{ + struct rockchip_drm_file_private *file_priv = file->driver_priv; + struct rockchip_drm_rga_private *rga_priv; + + rga_priv = kzalloc(sizeof(*rga_priv), GFP_KERNEL); + if (!rga_priv) + return -ENOMEM; + + rga_priv->dev = dev; + file_priv->rga_priv = rga_priv; + + INIT_LIST_HEAD(&rga_priv->inuse_cmdlist); + + return 0; +} + +static void rockchip_rga_close(struct drm_device *drm_dev, struct device *dev, + struct drm_file *file) +{ + struct rockchip_drm_file_private *file_priv = file->driver_priv; + struct rockchip_drm_rga_private *rga_priv = file_priv->rga_priv; + struct rga_cmdlist_node *node, *n; + struct rockchip_rga *rga; + + if (!dev) + return; + + rga = dev_get_drvdata(dev); + if (!rga) + return; + + mutex_lock(&rga->cmdlist_mutex); + list_for_each_entry_safe(node, n, &rga_priv->inuse_cmdlist, list) { + /* + * unmap all gem objects not completed. + * + * P.S. if current process was terminated forcely then + * there may be some commands in inuse_cmdlist so unmap + * them. + */ + rga_unmap_cmdlist_gem(rga, node); + list_move_tail(&node->list, &rga->free_cmdlist); + } + mutex_unlock(&rga->cmdlist_mutex); + + kfree(file_priv->rga_priv); +} + +static void rga_runqueue_worker(struct work_struct *work) +{ + struct rockchip_rga *rga = container_of(work, struct rockchip_rga, + runqueue_work); + + mutex_lock(&rga->runqueue_mutex); + pm_runtime_put_sync(rga->dev); + + complete(&rga->runqueue_node->complete); + + if (rga->suspended) + rga->runqueue_node = NULL; + else + rga_exec_runqueue(rga); + + mutex_unlock(&rga->runqueue_mutex); +} + +static irqreturn_t rga_irq_handler(int irq, void *dev_id) +{ + struct rockchip_rga *rga = dev_id; + int intr; + + intr = rga_read(rga, RGA_INT) & 0xf; + + rga_mod(rga, RGA_INT, intr << 4, 0xf << 4); + + if (intr & 0x04) + queue_work(rga->rga_workq, &rga->runqueue_work); + + return IRQ_HANDLED; +} + +static int rga_parse_dt(struct rockchip_rga *rga) +{ + struct reset_control *sclk_rst, *aclk_rst, *hclk_rst; + + sclk_rst = devm_reset_control_get(rga->dev, "sclk"); + if (IS_ERR(sclk_rst)) { + dev_err(rga->dev, "failed to get sclk reset controller\n"); + return PTR_ERR(sclk_rst); + } + + aclk_rst = devm_reset_control_get(rga->dev, "aclk"); + if (IS_ERR(aclk_rst)) { + dev_err(rga->dev, "failed to get aclk reset controller\n"); + return PTR_ERR(aclk_rst); + } + + hclk_rst = devm_reset_control_get(rga->dev, "hclk"); + if (IS_ERR(hclk_rst)) { + dev_err(rga->dev, "failed to get hclk reset controller\n"); + return PTR_ERR(hclk_rst); + } + + reset_control_assert(sclk_rst); + usleep_range(10, 20); + reset_control_deassert(sclk_rst); + + reset_control_assert(aclk_rst); + usleep_range(10, 20); + reset_control_deassert(aclk_rst); + + reset_control_assert(hclk_rst); + usleep_range(10, 20); + reset_control_deassert(hclk_rst); + + rga->sclk = devm_clk_get(rga->dev, "sclk"); + if (IS_ERR(rga->sclk)) { + dev_err(rga->dev, "failed to get sclk clock\n"); + return PTR_ERR(rga->sclk); + } + + rga->aclk = devm_clk_get(rga->dev, "aclk"); + if (IS_ERR(rga->aclk)) { + dev_err(rga->dev, "failed to get aclk clock\n"); + return PTR_ERR(rga->aclk); + } + + rga->hclk = devm_clk_get(rga->dev, "hclk"); + if (IS_ERR(rga->hclk)) { + dev_err(rga->dev, "failed to get hclk clock\n"); + return PTR_ERR(rga->hclk); + } + + return rga_enable_clocks(rga); +} + +static const struct of_device_id rockchip_rga_dt_ids[] = { + { .compatible = "rockchip,rk3288-rga", }, + { .compatible = "rockchip,rk3228-rga", }, + { .compatible = "rockchip,rk3399-rga", }, + {}, +}; +MODULE_DEVICE_TABLE(of, rockchip_rga_dt_ids); + +static int rga_probe(struct platform_device *pdev) +{ + struct drm_rockchip_subdrv *subdrv; + struct rockchip_rga *rga; + struct resource *iores; + int irq; + int ret; + + if (!pdev->dev.of_node) + return -ENODEV; + + rga = devm_kzalloc(&pdev->dev, sizeof(*rga), GFP_KERNEL); + if (!rga) + return -ENOMEM; + + rga->dev = &pdev->dev; + + rga->runqueue_slab = kmem_cache_create("rga_runqueue_slab", + sizeof(struct rga_runqueue_node), + 0, 0, NULL); + if (!rga->runqueue_slab) + return -ENOMEM; + + rga->rga_workq = create_singlethread_workqueue("rga"); + if (!rga->rga_workq) { + dev_err(rga->dev, "failed to create workqueue\n"); + goto err_destroy_slab; + } + + INIT_WORK(&rga->runqueue_work, rga_runqueue_worker); + INIT_LIST_HEAD(&rga->runqueue_list); + mutex_init(&rga->runqueue_mutex); + + INIT_LIST_HEAD(&rga->free_cmdlist); + mutex_init(&rga->cmdlist_mutex); + + rga_init_cmdlist(rga); + + ret = rga_parse_dt(rga); + if (ret) { + dev_err(rga->dev, "Unable to parse OF data\n"); + goto err_destroy_workqueue; + } + + pm_runtime_enable(rga->dev); + + iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + rga->regs = devm_ioremap_resource(rga->dev, iores); + if (IS_ERR(rga->regs)) { + ret = PTR_ERR(rga->regs); + goto err_put_clk; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(rga->dev, "failed to get irq\n"); + ret = irq; + goto err_put_clk; + } + + ret = devm_request_irq(rga->dev, irq, rga_irq_handler, 0, + dev_name(rga->dev), rga); + if (ret < 0) { + dev_err(rga->dev, "failed to request irq\n"); + goto err_put_clk; + } + + platform_set_drvdata(pdev, rga); + + rga->version.major = (rga_read(rga, RGA_VERSION_INFO) >> 24) & 0xFF; + rga->version.minor = (rga_read(rga, RGA_VERSION_INFO) >> 20) & 0x0F; + + subdrv = &rga->subdrv; + subdrv->dev = rga->dev; + subdrv->open = rockchip_rga_open; + subdrv->close = rockchip_rga_close; + + rockchip_register_subdrv(subdrv); + + return 0; + +err_put_clk: + pm_runtime_disable(rga->dev); +err_destroy_workqueue: + destroy_workqueue(rga->rga_workq); +err_destroy_slab: + kmem_cache_destroy(rga->runqueue_slab); + + return ret; +} + +static int rga_remove(struct platform_device *pdev) +{ + struct rockchip_rga *rga = platform_get_drvdata(pdev); + + cancel_work_sync(&rga->runqueue_work); + + while (rga->runqueue_node) { + rga_free_runqueue_node(rga, rga->runqueue_node); + rga->runqueue_node = rga_get_runqueue(rga); + } + + rockchip_unregister_subdrv(&rga->subdrv); + + return 0; +} + +static int rga_suspend(struct device *dev) +{ + struct rockchip_rga *rga = dev_get_drvdata(dev); + + mutex_lock(&rga->runqueue_mutex); + rga->suspended = true; + mutex_unlock(&rga->runqueue_mutex); + + flush_work(&rga->runqueue_work); + + return 0; +} + +static int rga_resume(struct device *dev) +{ + struct rockchip_rga *rga = dev_get_drvdata(dev); + + rga->suspended = false; + rga_exec_runqueue(rga); + + return 0; +} + +#ifdef CONFIG_PM +static int rga_runtime_suspend(struct device *dev) +{ + struct rockchip_rga *rga = dev_get_drvdata(dev); + + rga_disable_clocks(rga); + + return 0; +} + +static int rga_runtime_resume(struct device *dev) +{ + struct rockchip_rga *rga = dev_get_drvdata(dev); + + return rga_enable_clocks(rga); +} +#endif + +static const struct dev_pm_ops rga_pm = { + SET_SYSTEM_SLEEP_PM_OPS(rga_suspend, rga_resume) + SET_RUNTIME_PM_OPS(rga_runtime_suspend, + rga_runtime_resume, NULL) +}; + +static struct platform_driver rga_pltfm_driver = { + .probe = rga_probe, + .remove = rga_remove, + .driver = { + .name = "rockchip-rga", + .pm = &rga_pm, + .of_match_table = rockchip_rga_dt_ids, + }, +}; + +module_platform_driver(rga_pltfm_driver); + +MODULE_AUTHOR("Yakir Yang "); +MODULE_DESCRIPTION("Rockchip RGA Driver Extension"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:rockchip-rga"); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_rga.h b/drivers/gpu/drm/rockchip/rockchip_drm_rga.h new file mode 100644 index 0000000..4a8839a --- /dev/null +++ b/drivers/gpu/drm/rockchip/rockchip_drm_rga.h @@ -0,0 +1,108 @@ +#ifndef __ROCKCHIP_DRM_RGA__ +#define __ROCKCHIP_DRM_RGA__ + +#define RGA_CMDBUF_SIZE 14 +#define RGA_CMDLIST_SIZE 0x20 +#define RGA_CMDLIST_NUM 64 + +/* cmdlist data structure */ +struct rga_cmdlist { + u32 head; + unsigned long data[RGA_CMDLIST_SIZE * 2]; + u32 last; /* last data offset */ + void *src_mmu_pages; + void *dst_mmu_pages; + void *src1_mmu_pages; + struct dma_buf_attachment *src_attach; + struct dma_buf_attachment *dst_attach; +}; + +struct rga_cmdlist_node { + struct list_head list; + struct rga_cmdlist cmdlist; +}; + +struct rga_runqueue_node { + struct list_head list; + + struct device *dev; + pid_t pid; + struct drm_file *file; + struct completion complete; + + struct list_head run_cmdlist; + + int cmdlist_cnt; + void *cmdlist_pool_virt; + dma_addr_t cmdlist_pool; + struct dma_attrs cmdlist_dma_attrs; +}; + +struct rockchip_rga_version { + __u32 major; + __u32 minor; +}; + +struct rockchip_rga { + struct drm_device *drm_dev; + struct device *dev; + struct regmap *grf; + void __iomem *regs; + struct clk *sclk; + struct clk *aclk; + struct clk *hclk; + + bool suspended; + struct rockchip_rga_version version; + struct drm_rockchip_subdrv subdrv; + struct workqueue_struct *rga_workq; + struct work_struct runqueue_work; + + /* rga command list pool */ + struct rga_cmdlist_node cmdlist_node[RGA_CMDLIST_NUM]; + struct mutex cmdlist_mutex; + + struct list_head free_cmdlist; + + /* rga runqueue */ + struct rga_runqueue_node *runqueue_node; + struct list_head runqueue_list; + struct mutex runqueue_mutex; + struct kmem_cache *runqueue_slab; +}; + +struct rockchip_drm_rga_private { + struct device *dev; + struct list_head inuse_cmdlist; + struct list_head userptr_list; +}; + +#ifdef CONFIG_ROCKCHIP_DRM_RGA +int rockchip_rga_get_ver_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int rockchip_rga_set_cmdlist_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int rockchip_rga_exec_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +#else +static inline int rockchip_rga_get_ver_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + return -ENODEV; +} + +static inline int rockchip_rga_set_cmdlist_ioctl(struct drm_device *dev, + void *data, + struct drm_file *file_priv) +{ + return -ENODEV; +} + +static inline int rockchip_rga_exec_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + return -ENODEV; +} +#endif + +#endif /* __ROCKCHIP_DRM_RGA__ */ diff --git a/include/uapi/drm/rockchip_drm.h b/include/uapi/drm/rockchip_drm.h new file mode 100644 index 0000000..2e3e240 --- /dev/null +++ b/include/uapi/drm/rockchip_drm.h @@ -0,0 +1,63 @@ +/* rockchip_drm.h + * + * Copyright (c) 2016 Fuzhou Rockchip Electronics Co., Ltd. + * Authors: + * Yakir Yang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef _UAPI_ROCKCHIP_DRM_H_ +#define _UAPI_ROCKCHIP_DRM_H_ + +#include + +struct drm_rockchip_rga_get_ver { + __u32 major; + __u32 minor; +}; + +struct drm_rockchip_rga_cmd { + __u32 offset; + __u32 data; +}; + +enum drm_rockchip_rga_buf_type { + RGA_BUF_TYPE_USERPTR = 1 << 31, + RGA_BUF_TYPE_GEMFD = 1 << 30, +}; + +struct drm_rockchip_rga_userptr { + unsigned long userptr; + unsigned long size; +}; + +struct drm_rockchip_rga_set_cmdlist { + __u64 cmd; + __u64 cmd_buf; + __u32 cmd_nr; + __u32 cmd_buf_nr; + __u64 user_data; +}; + +struct drm_rockchip_rga_exec { + __u64 async; +}; + +#define DRM_ROCKCHIP_RGA_GET_VER 0x20 +#define DRM_ROCKCHIP_RGA_SET_CMDLIST 0x21 +#define DRM_ROCKCHIP_RGA_EXEC 0x22 + +#define DRM_IOCTL_ROCKCHIP_RGA_GET_VER DRM_IOWR(DRM_COMMAND_BASE + \ + DRM_ROCKCHIP_RGA_GET_VER, struct drm_rockchip_rga_get_ver) + +#define DRM_IOCTL_ROCKCHIP_RGA_SET_CMDLIST DRM_IOWR(DRM_COMMAND_BASE + \ + DRM_ROCKCHIP_RGA_SET_CMDLIST, struct drm_rockchip_rga_set_cmdlist) + +#define DRM_IOCTL_ROCKCHIP_RGA_EXEC DRM_IOWR(DRM_COMMAND_BASE + \ + DRM_ROCKCHIP_RGA_EXEC, struct drm_rockchip_rga_exec) + +#endif /* _UAPI_ROCKCHIP_DRM_H */ -- 1.9.1 From mboxrd@z Thu Jan 1 00:00:00 1970 From: Yakir Yang Subject: [RFC PATCH v1 2/4] drm: rockchip: add RGA driver support Date: Mon, 21 Mar 2016 17:40:06 +0800 Message-ID: <1458553206-26880-1-git-send-email-ykk@rock-chips.com> References: <1458552518-25527-1-git-send-email-ykk@rock-chips.com> Mime-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Return-path: In-Reply-To: <1458552518-25527-1-git-send-email-ykk@rock-chips.com> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" To: David Airlie , Mark Yao , Heiko Stuebner Cc: devicetree@vger.kernel.org, Russell King , Pawel Moll , Ian Campbell , linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-rockchip@lists.infradead.org, Rob Herring , Kumar Gala , linux-arm-kernel@lists.infradead.org List-Id: devicetree@vger.kernel.org Um9ja2NoaXAgUkdBIGlzIGEgc2VwYXJhdGUgMkQgcmFzdGVyIGdyYXBoaWMgYWNjZWxlcmF0aW9u IHVuaXQuIEl0CmFjY2VsZXJhdGVzIDJEIGdyYXBoaWNzIG9wZXJhdGlvbnMsIHN1Y2ggYXMgcG9p bnQvbGluZSBkcmF3aW5nLCBpbWFnZQpzY2FsaW5nLCByb3RhdGlvbiwgQml0QkxULCBhbHBoYSBi bGVuZGluZyBhbmQgaW1hZ2UgYmx1ci9zaGFycG5lc3MuCgpUaGUgUkdBIGRyaXZlciBpcyBiYXNl ZCBvbiBFeHlub3MgRzJEIGRyaXZlciwgaXQgaXMgcGVyZm9ybWVkIGJ5IHR3bwp0YXNrcyBzaW1w bHkuCjEuIENvbmZpZ3VyZXMgdGhlIHJlbmRlcmluZyBwYXJhbWV0ZXJzLCBzdWNoIGFzIGZvcmVn cm91bmQgY29sb3IgYW5kCiAgIGNvb3JkaW5hdGVzIGRhdGEgYnkgc2V0dGluZyB0aGUgZHJhd2lu ZyBjb250ZXh0IHJlZ2lzdGVycy4KMi4gU3RhcnQgdGhlIHJlbmRlcmluZyBwcm9jZXNzIGJ5IGNh bGxpbmcgcmdhX2V4ZWMoKSBpb2N0bC4KClRoZSBSR0Egc3VwcG9ydHMgRE1BIG1vZGUgYXMgaG9z dCBpbnRlcmZhY2UuIFVzZXIgY2FuIG1ha2UgY29tbWFuZCBsaXN0CnRvIHJlZHVjZSBIT1NUKEFS TSkgbG9hZHMuIFRoZSBjb250ZW50cyBvZiBUaGUgY29tbWFuZCBsaXN0IGlzIHNldHRlZCB0bwpy ZWxldmFudCByZWdpc3RlcnMgb2YgUkdBIGJ5IERNQS4KClRoZSBjb21tYW5kIGxpc3QgaXMgY29t cG9zZWQgSGVhZGVyIGFuZCBjb21tYW5kIHNldHMgYW5kIFRhaWwuCi0gSGVhZGVyOiBUaGUgbnVt YmVyIG9mIGNvbW1hbmQgc2V0KDRCeXRlcykKLSBDb21tYW5kIHNldDogUmVnaXN0ZXIgb2Zmc2V0 KDRCeXRlcykgKyBSZWdpc3RlciBkYXRhKDRCeXRlcykKLSBUYWlsOiBQb2ludGVyIG9mIGJhc2Ug YWRkcmVzcyBvZiB0aGUgb3RoZXIgY29tbWFuZCBsaXN0KDRCeXRlcykKCkJ5IFRhaWwgZmllbGQs IHRoZSBHMkQgY2FuIHByb2Nlc3MgbWFueSBjb21tYW5kIGxpc3RzIHdpdGhvdXQgaGFsdCBhdApv bmUgZ28uCgpUaGUgRzJEIGhhcyBmb2xsb3dpbmcgdGhlIHJlbmRlcmluZyBwaXBlbGluZS4KICAg ICAgICAgICAgICAgLS0tPiAgICAgQ29sb3IgRmlsbCAgICAgLS0tPgogICAgICAgICAgICAgICB8 ICAgICAgICAgICAgICAgICAgICAgICAgICB8Ci0tPiBETUEgKHJlYWQpIC0tLT4gU3JjIEJpdG1h cCBQcm9jZXNzIC0tLS0+IEFscGhhL1JPUCAtLS0+IEZvcm1hdCBjb252ZXJ0IC0tLT4gRE1BIChX cml0ZSkKICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgfAogICAgICAg ICAgICAgICAtLS0+IERzdCBCaXRtYXAgUHJvY2VzcyAtLS0+CgpBbmQgc3VwcG9ydHMgdmFyaW91 cyBvcGVyYXRpb25zIGZyb20gdGhlIHJlbmRlcmluZyBwaXBlbGluZS4KLSBjb3B5Ci0gZmFzdCBz b2xpZCBjb2xvciBmaWxsCi0gcm90YXRpb24KLSBmbGlwCi0gNCBvcGVyYW5kIHJhc3RlciBvcGVy YXRpb24oUk9QNCkKLSBhbHBoYSBibGVuZGluZwotIGNvbG9yIGtleQotIGRpdGhlcmluZwotIGV0 YwoKVXNlciBzaG91bGQgbWFrZSB0aGUgY29tbWFuZCBsaXN0IHRvIGRhdGEgYW5kIHJlZ2lzdGVy cyBuZWVkZWQgYnkKb3BlcmF0aW9uIHRvIHVzZS4gVGhlIFJvY2tjaGlwIFJHQSBkcml2ZXIgb25s eSBtYW5hZ2VzIHRoZSBjb21tYW5kIGxpc3RzCnJlY2VpdmVkIGZyb20gdXNlci4gU29tZSByZWdp c3RlcnMgbmVlZHMgbWVtb3J5IGJhc2UgYWRkcmVzcyhwaHlzaWNhbAphZGRyZXNzKSBvZiBpbWFn ZS4gVXNlciBkb2Vzbid0IGtub3cgaXRzIHBoeXNpY2FsIGFkZHJlc3MsIHNvIGZpbGxzIHRoZQpn ZW0gaGFuZGxlIG9mIHRoYXQgbWVtb3J5IHRoYW4gYWRkcmVzcyB0byBjb21tYW5kIHNldHMsIHRo ZW4gUkdBIGRyaXZlcgpjb252ZXJ0cyBpdCB0byBtZW1vcnkgYmFzZSBhZGRyZXNzLgoKV2UgYWRk cyB0aHJlZSBpb2N0bHMgZm9yIFJvY2tjaGlwIFJHQS4KCi0gaW9jdGxzCkRSTV9ST0NLQ0hJUF9S R0FfR0VUX1ZFUjogZ2V0IHRoZSBSR0EgaGFyZHdhcmUgdmVyc2lvbgpEUk1fUk9DS0NISVBfUkdB X1NFVF9DTURMSVNUOiBzZXQgdGhlIGNvbW1hbmQgbGlzdCBmcm9tIHVzZXIgdG8gZHJpdmVyCkRS TV9ST0NLQ0hJUF9SR0FfRVhFQzogZXhlY3V0ZSB0aGUgY29tbWFuZCBsaXN0cyBzZXR0ZWQgdG8g ZHJpdmVyCgpTaWduZWQtb2ZmLWJ5OiBZYWtpciBZYW5nIDx5a2tAcm9jay1jaGlwcy5jb20+Ci0t LQogLi4uL2JpbmRpbmdzL2Rpc3BsYXkvcm9ja2NoaXAvcm9ja2NoaXAtcmdhLnR4dCAgICAgfCAg MzYgKwogZHJpdmVycy9ncHUvZHJtL3JvY2tjaGlwL0tjb25maWcgICAgICAgICAgICAgICAgICAg fCAgIDkgKwogZHJpdmVycy9ncHUvZHJtL3JvY2tjaGlwL01ha2VmaWxlICAgICAgICAgICAgICAg ICAgfCAgIDEgKwogZHJpdmVycy9ncHUvZHJtL3JvY2tjaGlwL3JvY2tjaGlwX2RybV9kcnYuYyAg ICAgICAgfCAgMzUgKy0KIGRyaXZlcnMvZ3B1L2RybS9yb2NrY2hpcC9yb2NrY2hpcF9kcm1fZHJ2 LmggICAgICAgIHwgICA0ICsKIGRyaXZlcnMvZ3B1L2RybS9yb2NrY2hpcC9yb2NrY2hpcF9kcm1f cmdhLmMgICAgICAgIHwgOTc3ICsrKysrKysrKysrKysrKysrKysrKwogZHJpdmVycy9ncHUvZHJt L3JvY2tjaGlwL3JvY2tjaGlwX2RybV9yZ2EuaCAgICAgICAgfCAxMDggKysrCiBpbmNsdWRlL3Vh cGkvZHJtL3JvY2tjaGlwX2RybS5oICAgICAgICAgICAgICAgICAgICB8ICA2MyArKwogOCBmaWxl cyBjaGFuZ2VkLCAxMjMyIGluc2VydGlvbnMoKyksIDEgZGVsZXRpb24oLSkKIGNyZWF0ZSBtb2Rl IDEwMDY0NCBEb2N1bWVudGF0aW9uL2RldmljZXRyZWUvYmluZGluZ3MvZGlzcGxheS9yb2NrY2hp cC9yb2NrY2hpcC1yZ2EudHh0CiBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy9ncHUvZHJtL3Jv Y2tjaGlwL3JvY2tjaGlwX2RybV9yZ2EuYwogY3JlYXRlIG1vZGUgMTAwNjQ0IGRyaXZlcnMvZ3B1 L2RybS9yb2NrY2hpcC9yb2NrY2hpcF9kcm1fcmdhLmgKIGNyZWF0ZSBtb2RlIDEwMDY0NCBpbmNs dWRlL3VhcGkvZHJtL3JvY2tjaGlwX2RybS5oCgpkaWZmIC0tZ2l0IGEvRG9jdW1lbnRhdGlvbi9k ZXZpY2V0cmVlL2JpbmRpbmdzL2Rpc3BsYXkvcm9ja2NoaXAvcm9ja2NoaXAtcmdhLnR4dCBiL0Rv Y3VtZW50YXRpb24vZGV2aWNldHJlZS9iaW5kaW5ncy9kaXNwbGF5L3JvY2tjaGlwL3JvY2tjaGlw LXJnYS50eHQKbmV3IGZpbGUgbW9kZSAxMDA2NDQKaW5kZXggMDAwMDAwMC4uMGM2MDZjYgotLS0g L2Rldi9udWxsCisrKyBiL0RvY3VtZW50YXRpb24vZGV2aWNldHJlZS9iaW5kaW5ncy9kaXNwbGF5 L3JvY2tjaGlwL3JvY2tjaGlwLXJnYS50eHQKQEAgLTAsMCArMSwzNiBAQAorZGV2aWNlLXRyZWUg YmluZGluZ3MgZm9yIHJvY2tjaGlwIDJEIHJhc3RlciBncmFwaGljIGFjY2VsZXJhdGlvbiBjb250 cm9sbGVyIChSR0EpCisKK1JHQSBpcyBhIHNlcGFyYXRlIDJEIHJhc3RlciBncmFwaGljIGFjY2Vs ZXJhdGlvbiB1bml0LiBJdCBhY2NlbGVyYXRlcyAyRAorZ3JhcGhpY3Mgb3BlcmF0aW9ucywgc3Vj aCBhcyBwb2ludC9saW5lIGRyYXdpbmcsIGltYWdlIHNjYWxpbmcsIHJvdGF0aW9uLAorQml0QkxU LCBhbHBoYSBibGVuZGluZyBhbmQgaW1hZ2UgYmx1ci9zaGFycG5lc3MuCisKK1JlcXVpcmVkIHBy b3BlcnRpZXM6CistIGNvbXBhdGlibGU6IHZhbHVlIHNob3VsZCBiZSBvbmUgb2YgdGhlIGZvbGxv d2luZworCQkicm9ja2NoaXAscmszMjI4LXJnYSI7CisJCSJyb2NrY2hpcCxyazMyODgtcmdhIjsK KwkJInJvY2tjaGlwLHJrMzM5OS1yZ2EiOworCistIGludGVycnVwdHM6IFJHQSBpbnRlcnJ1cHQg bnVtYmVyLgorCistIGNsb2NrczogcGhhbmRsZSB0byBSR0Egc2Nsay9oY2xrL2FjbGsgY2xvY2tz CisKKy0gY2xvY2stbmFtZXM6IHNob3VsZCBiZSAiYWNsayIgImhjbGsiIGFuZCAic2NsayIKKwor LSByZXNldHM6IE11c3QgY29udGFpbiBhbiBlbnRyeSBmb3IgZWFjaCBlbnRyeSBpbiByZXNldC1u YW1lcy4KKyAgU2VlIC4uL3Jlc2V0L3Jlc2V0LnR4dCBmb3IgZGV0YWlscy4KKy0gcmVzZXQtbmFt ZXM6IHNob3VsZCBiZSAiYWNsayIgImhjbGsiIGFuZCAic2NsayIKKworRXhhbXBsZToKK1NvQyBz cGVjaWZpYyBEVCBlbnRyeToKKwlyZ2E6IHJnYUBmZjY4MDAwMCB7CisJCWNvbXBhdGlibGUgPSAi cm9ja2NoaXAscmszMzk5LXJnYSI7CisJCXJlZyA9IDwweGZmNjgwMDAwIDB4MTAwMDA+OworCQlp bnRlcnJ1cHRzID0gPEdJQ19TUEkgNTUgSVJRX1RZUEVfTEVWRUxfSElHSD47CisJCWludGVycnVw dC1uYW1lcyA9ICJyZ2EiOworCQljbG9ja3MgPSA8JmNydSBBQ0xLX1JHQT4sIDwmY3J1IEhDTEtf UkdBPiwgPCZjcnUgU0NMS19SR0E+OworCQljbG9jay1uYW1lcyA9ICJhY2xrIiwgImhjbGsiLCAi c2NsayI7CisKKwkJcmVzZXRzID0gPCZjcnUgU1JTVF9BX1JHQT4sIDwmY3J1IFNSU1RfSF9SR0E+ LCA8JmNydSBTUlNUX1JHQV9DT1JFPjsKKwkJcmVzZXQtbmFtZXMgPSAiYWNsayIsICJoY2xrIiwg InNjbGsiOworCQlzdGF0dXMgPSAiZGlzYWJsZWQiOworCX07CmRpZmYgLS1naXQgYS9kcml2ZXJz L2dwdS9kcm0vcm9ja2NoaXAvS2NvbmZpZyBiL2RyaXZlcnMvZ3B1L2RybS9yb2NrY2hpcC9LY29u ZmlnCmluZGV4IDc2YjMzNjIuLjIyMDIyMWIgMTAwNjQ0Ci0tLSBhL2RyaXZlcnMvZ3B1L2RybS9y b2NrY2hpcC9LY29uZmlnCisrKyBiL2RyaXZlcnMvZ3B1L2RybS9yb2NrY2hpcC9LY29uZmlnCkBA IC0xNiw2ICsxNiwxNSBAQCBjb25maWcgRFJNX1JPQ0tDSElQCiAJICAyRCBvciAzRCBhY2NlbGVy YXRpb247IGFjY2VsZXJhdGlvbiBpcyBwZXJmb3JtZWQgYnkgb3RoZXIKIAkgIElQIGZvdW5kIG9u IHRoZSBTb0MuCiAKK2NvbmZpZyBST0NLQ0hJUF9EUk1fUkdBCisJdHJpc3RhdGUgIlJvY2tjaGlw IFJHQSBzdXBwb3J0IgorCWRlcGVuZHMgb24gRFJNX1JPQ0tDSElQCisJaGVscAorCSAgQ2hvb3Nl IHRoaXMgb3B0aW9uIHRvIGVuYWJsZSBzdXBwb3J0IGZvciBSb2NrY2hpcCBSR0EuCisJICBSb2Nr Y2hpcCBSR0EgaXMgYSBraW5kIG9mIGhhcmR3YXJlIDJEIGFjY2VsZXJhdG9yLCBhbmQgaXQgc3Vw cG9ydAorCSAgc29saWQgcm9yYXRpb24sIHNjYWxpbmcsIGNvbG9yIGZvcm1hdCB0cmFuc2Zvcm0s IHNheSBZIHRvIGVuYWJsZSBpdHMKKwkgIGRyaXZlcgorCiBjb25maWcgUk9DS0NISVBfRFdfSERN SQogICAgICAgICB0cmlzdGF0ZSAiUm9ja2NoaXAgc3BlY2lmaWMgZXh0ZW5zaW9ucyBmb3IgU3lu b3BzeXMgRFcgSERNSSIKICAgICAgICAgZGVwZW5kcyBvbiBEUk1fUk9DS0NISVAKZGlmZiAtLWdp dCBhL2RyaXZlcnMvZ3B1L2RybS9yb2NrY2hpcC9NYWtlZmlsZSBiL2RyaXZlcnMvZ3B1L2RybS9y b2NrY2hpcC9NYWtlZmlsZQppbmRleCBkZjhmYmVmLi43ZGU1NDdjIDEwMDY0NAotLS0gYS9kcml2 ZXJzL2dwdS9kcm0vcm9ja2NoaXAvTWFrZWZpbGUKKysrIGIvZHJpdmVycy9ncHUvZHJtL3JvY2tj aGlwL01ha2VmaWxlCkBAIC05LDUgKzksNiBAQCByb2NrY2hpcGRybS0kKENPTkZJR19EUk1fRkJE RVZfRU1VTEFUSU9OKSArPSByb2NrY2hpcF9kcm1fZmJkZXYubwogb2JqLSQoQ09ORklHX1JPQ0tD SElQX0RXX0hETUkpICs9IGR3X2hkbWktcm9ja2NoaXAubwogb2JqLSQoQ09ORklHX1JPQ0tDSElQ X0RXX01JUElfRFNJKSArPSBkdy1taXBpLWRzaS5vCiBvYmotJChDT05GSUdfUk9DS0NISVBfSU5O T19IRE1JKSArPSBpbm5vX2hkbWkubworb2JqLSQoQ09ORklHX1JPQ0tDSElQX0RSTV9SR0EpICs9 IHJvY2tjaGlwX2RybV9yZ2EubwogCiBvYmotJChDT05GSUdfRFJNX1JPQ0tDSElQKSArPSByb2Nr Y2hpcGRybS5vIHJvY2tjaGlwX3ZvcF9yZWcubwpkaWZmIC0tZ2l0IGEvZHJpdmVycy9ncHUvZHJt L3JvY2tjaGlwL3JvY2tjaGlwX2RybV9kcnYuYyBiL2RyaXZlcnMvZ3B1L2RybS9yb2NrY2hpcC9y b2NrY2hpcF9kcm1fZHJ2LmMKaW5kZXggNGUwZmViMi4uMTYzOGJjOSAxMDA2NDQKLS0tIGEvZHJp dmVycy9ncHUvZHJtL3JvY2tjaGlwL3JvY2tjaGlwX2RybV9kcnYuYworKysgYi9kcml2ZXJzL2dw dS9kcm0vcm9ja2NoaXAvcm9ja2NoaXBfZHJtX2Rydi5jCkBAIC0yNSwxMCArMjUsMTMgQEAKICNp bmNsdWRlIDxsaW51eC9vZl9ncmFwaC5oPgogI2luY2x1ZGUgPGxpbnV4L2NvbXBvbmVudC5oPgog CisjaW5jbHVkZSA8ZHJtL3JvY2tjaGlwX2RybS5oPgorCiAjaW5jbHVkZSAicm9ja2NoaXBfZHJt X2Rydi5oIgogI2luY2x1ZGUgInJvY2tjaGlwX2RybV9mYi5oIgogI2luY2x1ZGUgInJvY2tjaGlw X2RybV9mYmRldi5oIgogI2luY2x1ZGUgInJvY2tjaGlwX2RybV9nZW0uaCIKKyNpbmNsdWRlICJy b2NrY2hpcF9kcm1fcmdhLmgiCiAKICNkZWZpbmUgRFJJVkVSX05BTUUJInJvY2tjaGlwIgogI2Rl ZmluZSBEUklWRVJfREVTQwkiUm9ja0NoaXAgU29jIERSTSIKQEAgLTI3NywxNiArMjgwLDI4IEBA IEVYUE9SVF9TWU1CT0xfR1BMKHJvY2tjaGlwX3VucmVnaXN0ZXJfc3ViZHJ2KTsKIAogc3RhdGlj IGludCByb2NrY2hpcF9kcm1fb3BlbihzdHJ1Y3QgZHJtX2RldmljZSAqZGV2LCBzdHJ1Y3QgZHJt X2ZpbGUgKmZpbGUpCiB7CisJc3RydWN0IHJvY2tjaGlwX2RybV9maWxlX3ByaXZhdGUgKmZpbGVf cHJpdjsKIAlzdHJ1Y3QgZHJtX3JvY2tjaGlwX3N1YmRydiAqc3ViZHJ2OwogCWludCByZXQgPSAw OwogCisJZmlsZV9wcml2ID0ga3phbGxvYyhzaXplb2YoKmZpbGVfcHJpdiksIEdGUF9LRVJORUwp OworCWlmICghZmlsZV9wcml2KQorCQlyZXR1cm4gLUVOT01FTTsKKworCWZpbGUtPmRyaXZlcl9w cml2ID0gZmlsZV9wcml2OworCiAJbGlzdF9mb3JfZWFjaF9lbnRyeShzdWJkcnYsICZyb2NrY2hp cF9kcm1fc3ViZHJ2X2xpc3QsIGxpc3QpIHsKIAkJcmV0ID0gc3ViZHJ2LT5vcGVuKGRldiwgc3Vi ZHJ2LT5kZXYsIGZpbGUpOwogCQlpZiAocmV0KQotCQkJcmV0dXJuIHJldDsKKwkJCWdvdG8gZXJy X2ZpbGVfcHJpdl9mcmVlOwogCX0KIAogCXJldHVybiAwOworCitlcnJfZmlsZV9wcml2X2ZyZWU6 CisJa2ZyZWUoZmlsZV9wcml2KTsKKwlmaWxlLT5kcml2ZXJfcHJpdiA9IE5VTEw7CisJcmV0dXJu IHJldDsKIH0KIAogc3RhdGljIHZvaWQgcm9ja2NoaXBfZHJtX3ByZWNsb3NlKHN0cnVjdCBkcm1f ZGV2aWNlICpkZXYsCkBAIC0yOTgsNiArMzEzLDEyIEBAIHN0YXRpYyB2b2lkIHJvY2tjaGlwX2Ry bV9wcmVjbG9zZShzdHJ1Y3QgZHJtX2RldmljZSAqZGV2LAogCQlzdWJkcnYtPmNsb3NlKGRldiwg c3ViZHJ2LT5kZXYsIGZpbGUpOwogfQogCitzdGF0aWMgdm9pZCByb2NrY2hpcF9kcm1fcG9zdGNs b3NlKHN0cnVjdCBkcm1fZGV2aWNlICpkZXYsCisJCQkJICAgc3RydWN0IGRybV9maWxlICpmaWxl KQoreworCWtmcmVlKGZpbGUtPmRyaXZlcl9wcml2KTsKK30KKwogdm9pZCByb2NrY2hpcF9kcm1f bGFzdGNsb3NlKHN0cnVjdCBkcm1fZGV2aWNlICpkZXYpCiB7CiAJc3RydWN0IHJvY2tjaGlwX2Ry bV9wcml2YXRlICpwcml2ID0gZGV2LT5kZXZfcHJpdmF0ZTsKQEAgLTMwNSw2ICszMjYsMTUgQEAg dm9pZCByb2NrY2hpcF9kcm1fbGFzdGNsb3NlKHN0cnVjdCBkcm1fZGV2aWNlICpkZXYpCiAJZHJt X2ZiX2hlbHBlcl9yZXN0b3JlX2ZiZGV2X21vZGVfdW5sb2NrZWQoJnByaXYtPmZiZGV2X2hlbHBl cik7CiB9CiAKK3N0YXRpYyBjb25zdCBzdHJ1Y3QgZHJtX2lvY3RsX2Rlc2Mgcm9ja2NoaXBfaW9j dGxzW10gPSB7CisJRFJNX0lPQ1RMX0RFRl9EUlYoUk9DS0NISVBfUkdBX0dFVF9WRVIsIHJvY2tj aGlwX3JnYV9nZXRfdmVyX2lvY3RsLAorCQkJICBEUk1fQVVUSCB8IERSTV9SRU5ERVJfQUxMT1cp LAorCURSTV9JT0NUTF9ERUZfRFJWKFJPQ0tDSElQX1JHQV9TRVRfQ01ETElTVCwgcm9ja2NoaXBf cmdhX3NldF9jbWRsaXN0X2lvY3RsLAorCQkJICBEUk1fQVVUSCB8IERSTV9SRU5ERVJfQUxMT1cp LAorCURSTV9JT0NUTF9ERUZfRFJWKFJPQ0tDSElQX1JHQV9FWEVDLCByb2NrY2hpcF9yZ2FfZXhl Y19pb2N0bCwKKwkJCSAgRFJNX0FVVEggfCBEUk1fUkVOREVSX0FMTE9XKSwKK307CisKIHN0YXRp YyBjb25zdCBzdHJ1Y3QgZmlsZV9vcGVyYXRpb25zIHJvY2tjaGlwX2RybV9kcml2ZXJfZm9wcyA9 IHsKIAkub3duZXIgPSBUSElTX01PRFVMRSwKIAkub3BlbiA9IGRybV9vcGVuLApAQCAtMzMwLDYg KzM2MCw3IEBAIHN0YXRpYyBzdHJ1Y3QgZHJtX2RyaXZlciByb2NrY2hpcF9kcm1fZHJpdmVyID0g ewogCS51bmxvYWQJCQk9IHJvY2tjaGlwX2RybV91bmxvYWQsCiAJLm9wZW4JCQk9IHJvY2tjaGlw X2RybV9vcGVuLAogCS5wcmVjbG9zZQkJPSByb2NrY2hpcF9kcm1fcHJlY2xvc2UsCisJLnBvc3Rj bG9zZQkJPSByb2NrY2hpcF9kcm1fcG9zdGNsb3NlLAogCS5sYXN0Y2xvc2UJCT0gcm9ja2NoaXBf ZHJtX2xhc3RjbG9zZSwKIAkuZ2V0X3ZibGFua19jb3VudGVyCT0gZHJtX3ZibGFua19ub19od19j b3VudGVyLAogCS5lbmFibGVfdmJsYW5rCQk9IHJvY2tjaGlwX2RybV9jcnRjX2VuYWJsZV92Ymxh bmssCkBAIC0zNDcsNiArMzc4LDggQEAgc3RhdGljIHN0cnVjdCBkcm1fZHJpdmVyIHJvY2tjaGlw X2RybV9kcml2ZXIgPSB7CiAJLmdlbV9wcmltZV92bWFwCQk9IHJvY2tjaGlwX2dlbV9wcmltZV92 bWFwLAogCS5nZW1fcHJpbWVfdnVubWFwCT0gcm9ja2NoaXBfZ2VtX3ByaW1lX3Z1bm1hcCwKIAku Z2VtX3ByaW1lX21tYXAJCT0gcm9ja2NoaXBfZ2VtX21tYXBfYnVmLAorCS5pb2N0bHMJCQk9IHJv Y2tjaGlwX2lvY3RscywKKwkubnVtX2lvY3RscwkJPSBBUlJBWV9TSVpFKHJvY2tjaGlwX2lvY3Rs cyksCiAJLmZvcHMJCQk9ICZyb2NrY2hpcF9kcm1fZHJpdmVyX2ZvcHMsCiAJLm5hbWUJPSBEUklW RVJfTkFNRSwKIAkuZGVzYwk9IERSSVZFUl9ERVNDLApkaWZmIC0tZ2l0IGEvZHJpdmVycy9ncHUv ZHJtL3JvY2tjaGlwL3JvY2tjaGlwX2RybV9kcnYuaCBiL2RyaXZlcnMvZ3B1L2RybS9yb2NrY2hp cC9yb2NrY2hpcF9kcm1fZHJ2LmgKaW5kZXggNWVhNWZjYi4uZWEzMGJhNiAxMDA2NDQKLS0tIGEv ZHJpdmVycy9ncHUvZHJtL3JvY2tjaGlwL3JvY2tjaGlwX2RybV9kcnYuaAorKysgYi9kcml2ZXJz L2dwdS9kcm0vcm9ja2NoaXAvcm9ja2NoaXBfZHJtX2Rydi5oCkBAIC01Myw2ICs1MywxMCBAQCBz dHJ1Y3QgZHJtX3JvY2tjaGlwX3N1YmRydiB7CiAJCSAgICAgIHN0cnVjdCBkcm1fZmlsZSAqZmls ZSk7CiB9OwogCitzdHJ1Y3Qgcm9ja2NoaXBfZHJtX2ZpbGVfcHJpdmF0ZSB7CisJc3RydWN0IHJv Y2tjaGlwX2RybV9yZ2FfcHJpdmF0ZSAqcmdhX3ByaXY7Cit9OworCiBzdHJ1Y3Qgcm9ja2NoaXBf YXRvbWljX2NvbW1pdCB7CiAJc3RydWN0IHdvcmtfc3RydWN0CXdvcms7CiAJc3RydWN0IGRybV9h dG9taWNfc3RhdGUgKnN0YXRlOwpkaWZmIC0tZ2l0IGEvZHJpdmVycy9ncHUvZHJtL3JvY2tjaGlw L3JvY2tjaGlwX2RybV9yZ2EuYyBiL2RyaXZlcnMvZ3B1L2RybS9yb2NrY2hpcC9yb2NrY2hpcF9k cm1fcmdhLmMKbmV3IGZpbGUgbW9kZSAxMDA2NDQKaW5kZXggMDAwMDAwMC4uNDIwMjEyMQotLS0g L2Rldi9udWxsCisrKyBiL2RyaXZlcnMvZ3B1L2RybS9yb2NrY2hpcC9yb2NrY2hpcF9kcm1fcmdh LmMKQEAgLTAsMCArMSw5NzcgQEAKKy8qCisgKiBDb3B5cmlnaHQgKEMpIEZ1emhvdSBSb2NrY2hp cCBFbGVjdHJvbmljcyBDby5MdGQKKyAqIEF1dGhvcjogWWFraXIgWWFuZyA8eWtrQHJvY2stY2hp cHMuY29tPgorICoKKyAqIGJhc2VkIG9uIGV4eW5vc19kcm1fZzJkLmMKKyAqCisgKiBUaGlzIHNv ZnR3YXJlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVi bGljCisgKiBMaWNlbnNlIHZlcnNpb24gMiwgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3 YXJlIEZvdW5kYXRpb24sIGFuZAorICogbWF5IGJlIGNvcGllZCwgZGlzdHJpYnV0ZWQsIGFuZCBt b2RpZmllZCB1bmRlciB0aG9zZSB0ZXJtcy4KKyAqCisgKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJp YnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCwKKyAqIGJ1dCBXSVRIT1VU IEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mCisgKiBN RVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUg dGhlCisgKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLgorICov CisKKyNpbmNsdWRlIDxsaW51eC9jbGsuaD4KKyNpbmNsdWRlIDxsaW51eC9kZWJ1Z2ZzLmg+Cisj aW5jbHVkZSA8bGludXgvZGVsYXkuaD4KKyNpbmNsdWRlIDxsaW51eC9kbWEtYnVmLmg+CisjaW5j bHVkZSA8bGludXgvZG1hLW1hcHBpbmcuaD4KKyNpbmNsdWRlIDxsaW51eC9pbnRlcnJ1cHQuaD4K KyNpbmNsdWRlIDxsaW51eC9vZi5oPgorI2luY2x1ZGUgPGxpbnV4L29mX2FkZHJlc3MuaD4KKyNp bmNsdWRlIDxsaW51eC9vZl9kZXZpY2UuaD4KKyNpbmNsdWRlIDxsaW51eC9wbV9ydW50aW1lLmg+ CisjaW5jbHVkZSA8bGludXgvcmVzZXQuaD4KKyNpbmNsdWRlIDxsaW51eC9zZXFfZmlsZS5oPgor I2luY2x1ZGUgPGxpbnV4L3NsYWIuaD4KKyNpbmNsdWRlIDxsaW51eC91YWNjZXNzLmg+CisKKyNp bmNsdWRlIDxhc20vY2FjaGVmbHVzaC5oPgorI2luY2x1ZGUgPGRybS9kcm1QLmg+CisjaW5jbHVk ZSA8ZHJtL3JvY2tjaGlwX2RybS5oPgorCisjaW5jbHVkZSAicm9ja2NoaXBfZHJtX2Rydi5oIgor I2luY2x1ZGUgInJvY2tjaGlwX2RybV9yZ2EuaCIKKworI2RlZmluZSBSR0FfTU9ERV9CQVNFX1JF RwkJMHgwMTAwCisjZGVmaW5lIFJHQV9NT0RFX01BWF9SRUcJCTB4MDE3QworCisjZGVmaW5lIFJH QV9TWVNfQ1RSTAkJCTB4MDAwMAorI2RlZmluZSBSR0FfQ01EX0NUUkwJCQkweDAwMDQKKyNkZWZp bmUgUkdBX0NNRF9CQVNFCQkJMHgwMDA4CisjZGVmaW5lIFJHQV9JTlQJCQkJMHgwMDEwCisjZGVm aW5lIFJHQV9NTVVfQ1RSTDAJCQkweDAwMTQKKyNkZWZpbmUgUkdBX1ZFUlNJT05fSU5GTwkJMHgw MDI4CisKKyNkZWZpbmUgUkdBX1NSQ19ZX1JHQl9CQVNFX0FERFIJCTB4MDEwOAorI2RlZmluZSBS R0FfU1JDX0NCX0JBU0VfQUREUgkJMHgwMTBDCisjZGVmaW5lIFJHQV9TUkNfQ1JfQkFTRV9BRERS CQkweDAxMTAKKyNkZWZpbmUgUkdBX1NSQzFfUkdCX0JBU0VfQUREUgkJMHgwMTE0CisjZGVmaW5l IFJHQV9EU1RfWV9SR0JfQkFTRV9BRERSCQkweDAxM0MKKyNkZWZpbmUgUkdBX0RTVF9DQl9CQVNF X0FERFIJCTB4MDE0MAorI2RlZmluZSBSR0FfRFNUX0NSX0JBU0VfQUREUgkJMHgwMTRDCisjZGVm aW5lIFJHQV9NTVVfQ1RSTDEJCQkweDAxNkMKKyNkZWZpbmUgUkdBX01NVV9TUkNfQkFTRQkJMHgw MTcwCisjZGVmaW5lIFJHQV9NTVVfU1JDMV9CQVNFCQkweDAxNzQKKyNkZWZpbmUgUkdBX01NVV9E U1RfQkFTRQkJMHgwMTc4CisKK3N0YXRpYyB2b2lkIHJnYV9kbWFfZmx1c2hfcmFuZ2Uodm9pZCAq cHRyLCBpbnQgc2l6ZSkKK3sKKyNpZmRlZiBDT05GSUdfQVJNCisJZG1hY19mbHVzaF9yYW5nZShw dHIsIHB0ciArIHNpemUpOworCW91dGVyX2ZsdXNoX3JhbmdlKHZpcnRfdG9fcGh5cyhwdHIpLCB2 aXJ0X3RvX3BoeXMocHRyICsgc2l6ZSkpOworI2VsaWYgQ09ORklHX0FSTTY0CisJX19kbWFfZmx1 c2hfcmFuZ2UocHRyLCBwdHIgKyBzaXplKTsKKyNlbmRpZgorfQorCitzdGF0aWMgaW5saW5lIHZv aWQgcmdhX3dyaXRlKHN0cnVjdCByb2NrY2hpcF9yZ2EgKnJnYSwgdTMyIHJlZywgdTMyIHZhbHVl KQoreworCXdyaXRlbCh2YWx1ZSwgcmdhLT5yZWdzICsgcmVnKTsKK30KKworc3RhdGljIGlubGlu ZSB1MzIgcmdhX3JlYWQoc3RydWN0IHJvY2tjaGlwX3JnYSAqcmdhLCB1MzIgcmVnKQoreworCXJl dHVybiByZWFkbChyZ2EtPnJlZ3MgKyByZWcpOworfQorCitzdGF0aWMgaW5saW5lIHZvaWQgcmdh X21vZChzdHJ1Y3Qgcm9ja2NoaXBfcmdhICpyZ2EsIHUzMiByZWcsIHUzMiB2YWwsIHUzMiBtYXNr KQoreworCXUzMiB0ZW1wID0gcmdhX3JlYWQocmdhLCByZWcpICYgfihtYXNrKTsKKworCXRlbXAg fD0gdmFsICYgbWFzazsKKwlyZ2Ffd3JpdGUocmdhLCByZWcsIHRlbXApOworfQorCitzdGF0aWMg aW50IHJnYV9lbmFibGVfY2xvY2tzKHN0cnVjdCByb2NrY2hpcF9yZ2EgKnJnYSkKK3sKKwlpbnQg cmV0OworCisJcmV0ID0gY2xrX3ByZXBhcmVfZW5hYmxlKHJnYS0+c2Nsayk7CisJaWYgKHJldCkg eworCQlkZXZfZXJyKHJnYS0+ZGV2LCAiQ2Fubm90IGVuYWJsZSByZ2Egc2NsazogJWRcbiIsIHJl dCk7CisJCXJldHVybiByZXQ7CisJfQorCisJcmV0ID0gY2xrX3ByZXBhcmVfZW5hYmxlKHJnYS0+ YWNsayk7CisJaWYgKHJldCkgeworCQlkZXZfZXJyKHJnYS0+ZGV2LCAiQ2Fubm90IGVuYWJsZSBy Z2EgYWNsazogJWRcbiIsIHJldCk7CisJCWdvdG8gZXJyX2Rpc2FibGVfc2NsazsKKwl9CisKKwly ZXQgPSBjbGtfcHJlcGFyZV9lbmFibGUocmdhLT5oY2xrKTsKKwlpZiAocmV0KSB7CisJCWRldl9l cnIocmdhLT5kZXYsICJDYW5ub3QgZW5hYmxlIHJnYSBoY2xrOiAlZFxuIiwgcmV0KTsKKwkJZ290 byBlcnJfZGlzYWJsZV9hY2xrOworCX0KKworCXJldHVybiAwOworCitlcnJfZGlzYWJsZV9zY2xr OgorCWNsa19kaXNhYmxlX3VucHJlcGFyZShyZ2EtPnNjbGspOworZXJyX2Rpc2FibGVfYWNsazoK KwljbGtfZGlzYWJsZV91bnByZXBhcmUocmdhLT5hY2xrKTsKKworCXJldHVybiByZXQ7Cit9CisK K3N0YXRpYyB2b2lkIHJnYV9kaXNhYmxlX2Nsb2NrcyhzdHJ1Y3Qgcm9ja2NoaXBfcmdhICpyZ2Ep Cit7CisJY2xrX2Rpc2FibGVfdW5wcmVwYXJlKHJnYS0+c2Nsayk7CisJY2xrX2Rpc2FibGVfdW5w cmVwYXJlKHJnYS0+aGNsayk7CisJY2xrX2Rpc2FibGVfdW5wcmVwYXJlKHJnYS0+YWNsayk7Cit9 CisKK3N0YXRpYyB2b2lkIHJnYV9pbml0X2NtZGxpc3Qoc3RydWN0IHJvY2tjaGlwX3JnYSAqcmdh KQoreworCXN0cnVjdCByZ2FfY21kbGlzdF9ub2RlICpub2RlOworCWludCBucjsKKworCW5vZGUg PSByZ2EtPmNtZGxpc3Rfbm9kZTsKKworCWZvciAobnIgPSAwOyBuciA8IEFSUkFZX1NJWkUocmdh LT5jbWRsaXN0X25vZGUpOyBucisrKQorCQlsaXN0X2FkZF90YWlsKCZub2RlW25yXS5saXN0LCAm cmdhLT5mcmVlX2NtZGxpc3QpOworfQorCitzdGF0aWMgaW50IHJnYV9hbGxvY19kbWFfYnVmX2Zv cl9jbWRsaXN0KHN0cnVjdCByZ2FfcnVucXVldWVfbm9kZSAqcnVucXVldWUpCit7CisJc3RydWN0 IGxpc3RfaGVhZCAqcnVuX2NtZGxpc3QgPSAmcnVucXVldWUtPnJ1bl9jbWRsaXN0OworCXN0cnVj dCBkZXZpY2UgKmRldiA9IHJ1bnF1ZXVlLT5kZXY7CisJc3RydWN0IGRtYV9hdHRycyBjbWRsaXN0 X2RtYV9hdHRyczsKKwlzdHJ1Y3QgcmdhX2NtZGxpc3Rfbm9kZSAqbm9kZTsKKwl2b2lkICpjbWRs aXN0X3Bvb2xfdmlydDsKKwlkbWFfYWRkcl90IGNtZGxpc3RfcG9vbDsKKwlpbnQgY21kbGlzdF9j bnQgPSAwOworCWludCBjb3VudCA9IDA7CisKKwlsaXN0X2Zvcl9lYWNoX2VudHJ5KG5vZGUsIHJ1 bl9jbWRsaXN0LCBsaXN0KQorCQljbWRsaXN0X2NudCsrOworCisJaW5pdF9kbWFfYXR0cnMoJmNt ZGxpc3RfZG1hX2F0dHJzKTsKKwlkbWFfc2V0X2F0dHIoRE1BX0FUVFJfV1JJVEVfQ09NQklORSwg JnJ1bnF1ZXVlLT5jbWRsaXN0X2RtYV9hdHRycyk7CisKKwljbWRsaXN0X3Bvb2xfdmlydCA9IGRt YV9hbGxvY19hdHRycyhkZXYsIGNtZGxpc3RfY250ICogUkdBX0NNRExJU1RfU0laRSwKKwkJCQkJ ICAgICZjbWRsaXN0X3Bvb2wsIEdGUF9LRVJORUwsCisJCQkJCSAgICAmY21kbGlzdF9kbWFfYXR0 cnMpOworCWlmICghY21kbGlzdF9wb29sX3ZpcnQpIHsKKwkJZGV2X2VycihkZXYsICJmYWlsZWQg dG8gYWxsb2NhdGUgY21kbGlzdCBkbWEgbWVtb3J5XG4iKTsKKwkJcmV0dXJuIC1FTk9NRU07CisJ fQorCisJLyoKKwkgKiBGaWxsIGluIHRoZSBSR0Egb3BlcmF0aW9uIHJlZ2lzdGVycyBmcm9tIGNt ZGxpc3QgY29tbWFuZCBidWZmZXIsCisJICogYW5kIGFsc28gZmlsbGVkIGluIHRoZSBNTVUgVExC IGJhc2UgaW5mb3JtYXRpb24uCisJICovCisJbGlzdF9mb3JfZWFjaF9lbnRyeShub2RlLCBydW5f Y21kbGlzdCwgbGlzdCkgeworCQlzdHJ1Y3QgcmdhX2NtZGxpc3QgKmNtZGxpc3QgPSAmbm9kZS0+ Y21kbGlzdDsKKwkJdW5zaWduZWQgaW50IG1tdV9jdHJsID0gMDsKKwkJdW5zaWduZWQgaW50ICpk ZXN0OworCQl1bnNpZ25lZCBpbnQgcmVnOworCQlpbnQgaTsKKworCQlkZXN0ID0gY21kbGlzdF9w b29sX3ZpcnQgKyBSR0FfQ01ETElTVF9TSVpFICogNCAqIGNvdW50Kys7CisKKwkJZm9yIChpID0g MDsgaSA8IGNtZGxpc3QtPmxhc3QgLyAyOyBpKyspIHsKKwkJCXJlZyA9IChub2RlLT5jbWRsaXN0 LmRhdGFbMiAqIGldIC0gUkdBX01PREVfQkFTRV9SRUcpOworCQkJaWYgKHJlZyA+IFJHQV9NT0RF X0JBU0VfUkVHKQorCQkJCWNvbnRpbnVlOworCQkJZGVzdFtyZWcgPDwgMl0gPSBjbWRsaXN0LT5k YXRhWzIgKiBpICsgMV07CisJCX0KKworCQlpZiAoY21kbGlzdC0+c3JjX21tdV9wYWdlcykgewor CQkJcmVnID0gUkdBX01NVV9TUkNfQkFTRSAtIFJHQV9NT0RFX0JBU0VfUkVHOworCQkJZGVzdFty ZWcgPDwgMl0gPSB2aXJ0X3RvX3BoeXMoY21kbGlzdC0+c3JjX21tdV9wYWdlcykgPj4gNDsKKwkJ CW1tdV9jdHJsIHw9IDB4NzsKKwkJfQorCisJCWlmIChjbWRsaXN0LT5kc3RfbW11X3BhZ2VzKSB7 CisJCQlyZWcgPSBSR0FfTU1VX0RTVF9CQVNFIC0gUkdBX01PREVfQkFTRV9SRUc7CisJCQlkZXN0 W3JlZyA8PCAyXSA9IHZpcnRfdG9fcGh5cyhjbWRsaXN0LT5kc3RfbW11X3BhZ2VzKSA+PiA0Owor CQkJbW11X2N0cmwgfD0gMHg3IDw8IDg7CisJCX0KKworCQlpZiAoY21kbGlzdC0+c3JjMV9tbXVf cGFnZXMpIHsKKwkJCXJlZyA9IFJHQV9NTVVfU1JDMV9CQVNFIC0gUkdBX01PREVfQkFTRV9SRUc7 CisJCQlkZXN0W3JlZyA8PCAyXSA9IHZpcnRfdG9fcGh5cyhjbWRsaXN0LT5zcmMxX21tdV9wYWdl cykgPj4gNDsKKwkJCW1tdV9jdHJsIHw9IDB4NyA8PCA0OworCQl9CisKKwkJcmVnID0gUkdBX01N VV9DVFJMMSAtIFJHQV9NT0RFX0JBU0VfUkVHOworCQlkZXN0W3JlZyA8PCAyXSA9IG1tdV9jdHJs OworCX0KKworCXJnYV9kbWFfZmx1c2hfcmFuZ2UoY21kbGlzdF9wb29sX3ZpcnQsIGNtZGxpc3Rf Y250ICogUkdBX0NNRExJU1RfU0laRSk7CisKKwlydW5xdWV1ZS0+Y21kbGlzdF9kbWFfYXR0cnMg PSBjbWRsaXN0X2RtYV9hdHRyczsKKwlydW5xdWV1ZS0+Y21kbGlzdF9wb29sX3ZpcnQgPSBjbWRs aXN0X3Bvb2xfdmlydDsKKwlydW5xdWV1ZS0+Y21kbGlzdF9wb29sID0gY21kbGlzdF9wb29sOwor CXJ1bnF1ZXVlLT5jbWRsaXN0X2NudCA9IGNtZGxpc3RfY250OworCisJcmV0dXJuIDA7Cit9CisK K3N0YXRpYyBpbnQgcmdhX2NoZWNrX3JlZ19vZmZzZXQoc3RydWN0IGRldmljZSAqZGV2LAorCQkJ CXN0cnVjdCByZ2FfY21kbGlzdF9ub2RlICpub2RlKQoreworCXN0cnVjdCByZ2FfY21kbGlzdCAq Y21kbGlzdCA9ICZub2RlLT5jbWRsaXN0OworCWludCBpbmRleDsKKwlpbnQgcmVnOworCWludCBp OworCisJZm9yIChpID0gMDsgaSA8IGNtZGxpc3QtPmxhc3QgLyAyOyBpKyspIHsKKwkJaW5kZXgg PSBjbWRsaXN0LT5sYXN0IC0gMiAqIChpICsgMSk7CisJCXJlZyA9IGNtZGxpc3QtPmRhdGFbaW5k ZXhdOworCisJCXN3aXRjaCAocmVnKSB7CisJCWNhc2UgUkdBX0JVRl9UWVBFX0dFTUZEIHwgUkdB X0RTVF9ZX1JHQl9CQVNFX0FERFI6CisJCWNhc2UgUkdBX0JVRl9UWVBFX0dFTUZEIHwgUkdBX1NS Q19ZX1JHQl9CQVNFX0FERFI6CisJCQlicmVhazsKKworCQljYXNlIFJHQV9CVUZfVFlQRV9VU0VS UFRSIHwgUkdBX0RTVF9ZX1JHQl9CQVNFX0FERFI6CisJCWNhc2UgUkdBX0JVRl9UWVBFX1VTRVJQ VFIgfCBSR0FfU1JDX1lfUkdCX0JBU0VfQUREUjoKKwkJCWdvdG8gZXJyOworCisJCWRlZmF1bHQ6 CisJCQlpZiAocmVnIDwgUkdBX01PREVfQkFTRV9SRUcgfHwgcmVnID4gUkdBX01PREVfTUFYX1JF RykKKwkJCQlnb3RvIGVycjsKKworCQkJaWYgKHJlZyAlIDQpCisJCQkJZ290byBlcnI7CisJCX0K Kwl9CisKKwlyZXR1cm4gMDsKKworZXJyOgorCWRldl9lcnIoZGV2LCAiQmFkIHJlZ2lzdGVyIG9m ZnNldDogMHglbHhcbiIsIGNtZGxpc3QtPmRhdGFbaW5kZXhdKTsKKwlyZXR1cm4gLUVJTlZBTDsK K30KKworc3RhdGljIHN0cnVjdCBkbWFfYnVmX2F0dGFjaG1lbnQgKgorcmdhX2dlbV9idWZfdG9f cGFnZXMoc3RydWN0IHJvY2tjaGlwX3JnYSAqcmdhLCB2b2lkICoqbW11X3BhZ2VzLCBpbnQgZmQp Cit7CisJc3RydWN0IGRtYV9idWZfYXR0YWNobWVudCAqYXR0YWNoOworCXN0cnVjdCBkbWFfYnVm ICpkbWFidWY7CisJc3RydWN0IHNnX3RhYmxlICpzZ3Q7CisJc3RydWN0IHNjYXR0ZXJsaXN0ICpz Z2w7CisJdW5zaWduZWQgaW50IG1hcHBlZF9zaXplID0gMDsKKwl1bnNpZ25lZCBpbnQgYWRkcmVz czsKKwl1bnNpZ25lZCBpbnQgbGVuOworCXVuc2lnbmVkIGludCBpLCBwOworCXVuc2lnbmVkIGlu dCAqcGFnZXM7CisJaW50IHJldDsKKworCWRtYWJ1ZiA9IGRtYV9idWZfZ2V0KGZkKTsKKwlpZiAo SVNfRVJSKGRtYWJ1ZikpIHsKKwkJZGV2X2VycihyZ2EtPmRldiwgIkZhaWxlZCB0byBnZXQgZG1h X2J1ZiB3aXRoIGZkICVkXG4iLCBmZCk7CisJCXJldHVybiBFUlJfUFRSKC1FSU5WQUwpOworCX0K KworCWF0dGFjaCA9IGRtYV9idWZfYXR0YWNoKGRtYWJ1ZiwgcmdhLT5kZXYpOworCWlmIChJU19F UlIoYXR0YWNoKSkgeworCQlkZXZfZXJyKHJnYS0+ZGV2LCAiRmFpbGVkIHRvIGF0dGFjaCBkbWFf YnVmXG4iKTsKKwkJcmV0ID0gUFRSX0VSUihhdHRhY2gpOworCQlnb3RvIGZhaWxlZF9hdHRhY2g7 CisJfQorCisJc2d0ID0gZG1hX2J1Zl9tYXBfYXR0YWNobWVudChhdHRhY2gsIERNQV9CSURJUkVD VElPTkFMKTsKKwlpZiAoSVNfRVJSKHNndCkpIHsKKwkJZGV2X2VycihyZ2EtPmRldiwgIkZhaWxl ZCB0byBtYXAgZG1hX2J1ZiBhdHRhY2htZW50XG4iKTsKKwkJcmV0ID0gUFRSX0VSUihzZ3QpOwor CQlnb3RvIGZhaWxlZF9kZXRhY2g7CisJfQorCisJLyoKKwkgKiBBbGxvYyAoMl4zICogNEspID0g MzJLIGJ5dGUgZm9yIHN0b3JpbmcgcGFnZXMsIHRob3NlIHNwYWNlIGNvdWxkCisJICogY292ZXIg MzJLICogNEsgPSAxMjhNIHJhbSBhZGRyZXNzLgorCSAqLworCXBhZ2VzID0gKHVuc2lnbmVkIGlu dCAqKV9fZ2V0X2ZyZWVfcGFnZXMoR0ZQX0tFUk5FTCB8IF9fR0ZQX1pFUk8sIDMpOworCisJZm9y X2VhY2hfc2coc2d0LT5zZ2wsIHNnbCwgc2d0LT5uZW50cywgaSkgeworCQlsZW4gPSBzZ19kbWFf bGVuKHNnbCkgPj4gUEFHRV9TSElGVDsKKwkJYWRkcmVzcyA9IHNnX3BoeXMoc2dsKTsKKworCQlm b3IgKHAgPSAwOyBwIDwgbGVuOyBwKyspIHsKKwkJCWRtYV9hZGRyX3QgcGh5cyA9IGFkZHJlc3Mg KyAocCA8PCBQQUdFX1NISUZUKTsKKwkJCXZvaWQgKnZpcnQgPSBwaHlzX3RvX3ZpcnQocGh5cyk7 CisKKwkJCXJnYV9kbWFfZmx1c2hfcmFuZ2UodmlydCwgNCAqIDEwMjQpOworCQkJcGFnZXNbbWFw cGVkX3NpemUgKyBwXSA9IHBoeXM7CisJCX0KKworCQltYXBwZWRfc2l6ZSArPSBsZW47CisJfQor CisJcmdhX2RtYV9mbHVzaF9yYW5nZShwYWdlcywgMzIgKiAxMDI0KTsKKworCSptbXVfcGFnZXMg PSBwYWdlczsKKworCWRtYV9idWZfdW5tYXBfYXR0YWNobWVudChhdHRhY2gsIHNndCwgRE1BX0JJ RElSRUNUSU9OQUwpOworCisJcmV0dXJuIGF0dGFjaDsKKworZmFpbGVkX2RldGFjaDoKKwlkbWFf YnVmX2RldGFjaChkbWFidWYsIGF0dGFjaCk7CitmYWlsZWRfYXR0YWNoOgorCWRtYV9idWZfcHV0 KGRtYWJ1Zik7CisKKwlyZXR1cm4gRVJSX1BUUihyZXQpOworfQorCitzdGF0aWMgaW50IHJnYV9t YXBfY21kbGlzdF9nZW0oc3RydWN0IHJvY2tjaGlwX3JnYSAqcmdhLAorCQkJICAgICAgIHN0cnVj dCByZ2FfY21kbGlzdF9ub2RlICpub2RlLAorCQkJICAgICAgIHN0cnVjdCBkcm1fZGV2aWNlICpk cm1fZGV2LAorCQkJICAgICAgIHN0cnVjdCBkcm1fZmlsZSAqZmlsZSkKK3sKKwlzdHJ1Y3Qgcmdh X2NtZGxpc3QgKmNtZGxpc3QgPSAmbm9kZS0+Y21kbGlzdDsKKwlzdHJ1Y3QgZG1hX2J1Zl9hdHRh Y2htZW50ICphdHRhY2g7CisJdm9pZCAqbW11X3BhZ2VzOworCWludCBmZDsKKwlpbnQgaTsKKwor CWZvciAoaSA9IDA7IGkgPCBjbWRsaXN0LT5sYXN0IC8gMjsgaSsrKSB7CisJCWludCBpbmRleCA9 IGNtZGxpc3QtPmxhc3QgLSAyICogKGkgKyAxKTsKKworCQlzd2l0Y2ggKGNtZGxpc3QtPmRhdGFb aW5kZXhdKSB7CisJCWNhc2UgUkdBX1NSQ19ZX1JHQl9CQVNFX0FERFIgfCBSR0FfQlVGX1RZUEVf R0VNRkQ6CisJCQlmZCA9IGNtZGxpc3QtPmRhdGFbaW5kZXggKyAxXTsKKwkJCWF0dGFjaCA9IHJn YV9nZW1fYnVmX3RvX3BhZ2VzKHJnYSwgJm1tdV9wYWdlcywgZmQpOworCisJCQljbWRsaXN0LT5z cmNfYXR0YWNoID0gYXR0YWNoOworCQkJY21kbGlzdC0+c3JjX21tdV9wYWdlcyA9IG1tdV9wYWdl czsKKwkJCWJyZWFrOworCisJCWNhc2UgUkdBX0RTVF9ZX1JHQl9CQVNFX0FERFIgfCBSR0FfQlVG X1RZUEVfR0VNRkQ6CisJCQlmZCA9IGNtZGxpc3QtPmRhdGFbaW5kZXggKyAxXTsKKwkJCWF0dGFj aCA9IHJnYV9nZW1fYnVmX3RvX3BhZ2VzKHJnYSwgJm1tdV9wYWdlcywgZmQpOworCisJCQljbWRs aXN0LT5kc3RfYXR0YWNoID0gYXR0YWNoOworCQkJY21kbGlzdC0+ZHN0X21tdV9wYWdlcyA9IG1t dV9wYWdlczsKKwkJCWJyZWFrOworCQl9CisJfQorCisJcmV0dXJuIDA7Cit9CisKK3N0YXRpYyB2 b2lkIHJnYV91bm1hcF9jbWRsaXN0X2dlbShzdHJ1Y3Qgcm9ja2NoaXBfcmdhICpyZ2EsCisJCQkJ ICBzdHJ1Y3QgcmdhX2NtZGxpc3Rfbm9kZSAqbm9kZSkKK3sKKwlzdHJ1Y3QgZG1hX2J1Zl9hdHRh Y2htZW50ICphdHRhY2g7CisJc3RydWN0IGRtYV9idWYgKmRtYV9idWY7CisKKwlhdHRhY2ggPSBu b2RlLT5jbWRsaXN0LnNyY19hdHRhY2g7CisJaWYgKGF0dGFjaCkgeworCQlkbWFfYnVmID0gYXR0 YWNoLT5kbWFidWY7CisJCWRtYV9idWZfZGV0YWNoKGRtYV9idWYsIGF0dGFjaCk7CisJCWRtYV9i dWZfcHV0KGRtYV9idWYpOworCX0KKwlub2RlLT5jbWRsaXN0LnNyY19hdHRhY2ggPSBOVUxMOwor CisJYXR0YWNoID0gbm9kZS0+Y21kbGlzdC5kc3RfYXR0YWNoOworCWlmIChhdHRhY2gpIHsKKwkJ ZG1hX2J1ZiA9IGF0dGFjaC0+ZG1hYnVmOworCQlkbWFfYnVmX2RldGFjaChkbWFfYnVmLCBhdHRh Y2gpOworCQlkbWFfYnVmX3B1dChkbWFfYnVmKTsKKwl9CisJbm9kZS0+Y21kbGlzdC5kc3RfYXR0 YWNoID0gTlVMTDsKKworCWlmIChub2RlLT5jbWRsaXN0LnNyY19tbXVfcGFnZXMpCisJCWZyZWVf cGFnZXMoKHVuc2lnbmVkIGxvbmcpbm9kZS0+Y21kbGlzdC5zcmNfbW11X3BhZ2VzLCAzKTsKKwlu b2RlLT5jbWRsaXN0LnNyY19tbXVfcGFnZXMgPSBOVUxMOworCisJaWYgKG5vZGUtPmNtZGxpc3Qu c3JjMV9tbXVfcGFnZXMpCisJCWZyZWVfcGFnZXMoKHVuc2lnbmVkIGxvbmcpbm9kZS0+Y21kbGlz dC5zcmMxX21tdV9wYWdlcywgMyk7CisJbm9kZS0+Y21kbGlzdC5zcmMxX21tdV9wYWdlcyA9IE5V TEw7CisKKwlpZiAobm9kZS0+Y21kbGlzdC5kc3RfbW11X3BhZ2VzKQorCQlmcmVlX3BhZ2VzKCh1 bnNpZ25lZCBsb25nKW5vZGUtPmNtZGxpc3QuZHN0X21tdV9wYWdlcywgMyk7CisJbm9kZS0+Y21k bGlzdC5kc3RfbW11X3BhZ2VzID0gTlVMTDsKK30KKworc3RhdGljIHZvaWQgcmdhX2NtZF9zdGFy dChzdHJ1Y3Qgcm9ja2NoaXBfcmdhICpyZ2EsCisJCQkgIHN0cnVjdCByZ2FfcnVucXVldWVfbm9k ZSAqcnVucXVldWUpCit7CisJaW50IHJldDsKKworCXJldCA9IHBtX3J1bnRpbWVfZ2V0X3N5bmMo cmdhLT5kZXYpOworCWlmIChyZXQgPCAwKQorCQlyZXR1cm47CisKKwlyZ2Ffd3JpdGUocmdhLCBS R0FfU1lTX0NUUkwsIDB4MDApOworCisJcmdhX3dyaXRlKHJnYSwgUkdBX0NNRF9CQVNFLCBydW5x dWV1ZS0+Y21kbGlzdF9wb29sKTsKKworCXJnYV93cml0ZShyZ2EsIFJHQV9TWVNfQ1RSTCwgMHgy Mik7CisKKwlyZ2Ffd3JpdGUocmdhLCBSR0FfSU5ULCAweDYwMCk7CisKKwlyZ2Ffd3JpdGUocmdh LCBSR0FfQ01EX0NUUkwsICgocnVucXVldWUtPmNtZGxpc3RfY250IC0gMSkgPDwgMykgfCAweDEp OworfQorCitzdGF0aWMgdm9pZCByZ2FfZnJlZV9ydW5xdWV1ZV9ub2RlKHN0cnVjdCByb2NrY2hp cF9yZ2EgKnJnYSwKKwkJCQkgICBzdHJ1Y3QgcmdhX3J1bnF1ZXVlX25vZGUgKnJ1bnF1ZXVlKQor eworCXN0cnVjdCByZ2FfY21kbGlzdF9ub2RlICpub2RlOworCisJaWYgKCFydW5xdWV1ZSkKKwkJ cmV0dXJuOworCisJaWYgKHJ1bnF1ZXVlLT5jbWRsaXN0X3Bvb2xfdmlydCAmJiBydW5xdWV1ZS0+ Y21kbGlzdF9wb29sKQorCQlkbWFfZnJlZV9hdHRycyhyZ2EtPmRldiwgcnVucXVldWUtPmNtZGxp c3RfY250ICogUkdBX0NNRExJU1RfU0laRSwKKwkJCSAgICAgICBydW5xdWV1ZS0+Y21kbGlzdF9w b29sX3ZpcnQsCisJCQkgICAgICAgcnVucXVldWUtPmNtZGxpc3RfcG9vbCwKKwkJCSAgICAgICAm cnVucXVldWUtPmNtZGxpc3RfZG1hX2F0dHJzKTsKKworCW11dGV4X2xvY2soJnJnYS0+Y21kbGlz dF9tdXRleCk7CisJLyoKKwkgKiBjb21tYW5kcyBpbiBydW5fY21kbGlzdCBoYXZlIGJlZW4gY29t cGxldGVkIHNvIHVubWFwIGFsbCBnZW0KKwkgKiBvYmplY3RzIGluIGVhY2ggY29tbWFuZCBub2Rl IHNvIHRoYXQgdGhleSBhcmUgdW5yZWZlcmVuY2VkLgorCSAqLworCWxpc3RfZm9yX2VhY2hfZW50 cnkobm9kZSwgJnJ1bnF1ZXVlLT5ydW5fY21kbGlzdCwgbGlzdCkKKwkJcmdhX3VubWFwX2NtZGxp c3RfZ2VtKHJnYSwgbm9kZSk7CisJbGlzdF9zcGxpY2VfdGFpbF9pbml0KCZydW5xdWV1ZS0+cnVu X2NtZGxpc3QsICZyZ2EtPmZyZWVfY21kbGlzdCk7CisJbXV0ZXhfdW5sb2NrKCZyZ2EtPmNtZGxp c3RfbXV0ZXgpOworCisJa21lbV9jYWNoZV9mcmVlKHJnYS0+cnVucXVldWVfc2xhYiwgcnVucXVl dWUpOworfQorCitzdGF0aWMgc3RydWN0IHJnYV9ydW5xdWV1ZV9ub2RlICpyZ2FfZ2V0X3J1bnF1 ZXVlKHN0cnVjdCByb2NrY2hpcF9yZ2EgKnJnYSkKK3sKKwlzdHJ1Y3QgcmdhX3J1bnF1ZXVlX25v ZGUgKnJ1bnF1ZXVlOworCisJaWYgKGxpc3RfZW1wdHkoJnJnYS0+cnVucXVldWVfbGlzdCkpCisJ CXJldHVybiBOVUxMOworCisJcnVucXVldWUgPSBsaXN0X2ZpcnN0X2VudHJ5KCZyZ2EtPnJ1bnF1 ZXVlX2xpc3QsCisJCQkJICAgIHN0cnVjdCByZ2FfcnVucXVldWVfbm9kZSwgbGlzdCk7CisJbGlz dF9kZWxfaW5pdCgmcnVucXVldWUtPmxpc3QpOworCisJcmV0dXJuIHJ1bnF1ZXVlOworfQorCitz dGF0aWMgdm9pZCByZ2FfZXhlY19ydW5xdWV1ZShzdHJ1Y3Qgcm9ja2NoaXBfcmdhICpyZ2EpCit7 CisJcmdhLT5ydW5xdWV1ZV9ub2RlID0gcmdhX2dldF9ydW5xdWV1ZShyZ2EpOworCWlmIChyZ2Et PnJ1bnF1ZXVlX25vZGUpCisJCXJnYV9jbWRfc3RhcnQocmdhLCByZ2EtPnJ1bnF1ZXVlX25vZGUp OworfQorCitzdGF0aWMgc3RydWN0IHJnYV9jbWRsaXN0X25vZGUgKnJnYV9nZXRfY21kbGlzdChz dHJ1Y3Qgcm9ja2NoaXBfcmdhICpyZ2EpCit7CisJc3RydWN0IHJnYV9jbWRsaXN0X25vZGUgKm5v ZGU7CisJc3RydWN0IGRldmljZSAqZGV2ID0gcmdhLT5kZXY7CisKKwltdXRleF9sb2NrKCZyZ2Et PmNtZGxpc3RfbXV0ZXgpOworCWlmIChsaXN0X2VtcHR5KCZyZ2EtPmZyZWVfY21kbGlzdCkpIHsK KwkJZGV2X2VycihkZXYsICJ0aGVyZSBpcyBubyBmcmVlIGNtZGxpc3RcbiIpOworCQltdXRleF91 bmxvY2soJnJnYS0+Y21kbGlzdF9tdXRleCk7CisJCXJldHVybiBOVUxMOworCX0KKworCW5vZGUg PSBsaXN0X2ZpcnN0X2VudHJ5KCZyZ2EtPmZyZWVfY21kbGlzdCwKKwkJCQlzdHJ1Y3QgcmdhX2Nt ZGxpc3Rfbm9kZSwgbGlzdCk7CisJbGlzdF9kZWxfaW5pdCgmbm9kZS0+bGlzdCk7CisJbXV0ZXhf dW5sb2NrKCZyZ2EtPmNtZGxpc3RfbXV0ZXgpOworCisJcmV0dXJuIG5vZGU7Cit9CisKK3N0YXRp YyB2b2lkIHJnYV9hZGRfY21kbGlzdF90b19pbnVzZShzdHJ1Y3Qgcm9ja2NoaXBfZHJtX3JnYV9w cml2YXRlICpyZ2FfcHJpdiwKKwkJCQkgICAgIHN0cnVjdCByZ2FfY21kbGlzdF9ub2RlICpub2Rl KQoreworCXN0cnVjdCByZ2FfY21kbGlzdF9ub2RlICpsbm9kZTsKKworCWlmIChsaXN0X2VtcHR5 KCZyZ2FfcHJpdi0+aW51c2VfY21kbGlzdCkpCisJCWdvdG8gYWRkX3RvX2xpc3Q7CisKKwkvKiB0 aGlzIGxpbmtzIHRvIGJhc2UgYWRkcmVzcyBvZiBuZXcgY21kbGlzdCAqLworCWxub2RlID0gbGlz dF9lbnRyeShyZ2FfcHJpdi0+aW51c2VfY21kbGlzdC5wcmV2LAorCQkJICAgc3RydWN0IHJnYV9j bWRsaXN0X25vZGUsIGxpc3QpOworCithZGRfdG9fbGlzdDoKKwlsaXN0X2FkZF90YWlsKCZub2Rl LT5saXN0LCAmcmdhX3ByaXYtPmludXNlX2NtZGxpc3QpOworfQorCisvKgorICogSU9DUkwgZnVu Y3Rpb25zIGZvciB1c2Vyc3BhY2UgdG8gZ2V0IFJHQSB2ZXJzaW9uLgorICovCitpbnQgcm9ja2No aXBfcmdhX2dldF92ZXJfaW9jdGwoc3RydWN0IGRybV9kZXZpY2UgKmRybV9kZXYsIHZvaWQgKmRh dGEsCisJCQkgICAgICAgc3RydWN0IGRybV9maWxlICpmaWxlKQoreworCXN0cnVjdCByb2NrY2hp cF9kcm1fZmlsZV9wcml2YXRlICpmaWxlX3ByaXYgPSBmaWxlLT5kcml2ZXJfcHJpdjsKKwlzdHJ1 Y3Qgcm9ja2NoaXBfZHJtX3JnYV9wcml2YXRlICpyZ2FfcHJpdiA9IGZpbGVfcHJpdi0+cmdhX3By aXY7CisJc3RydWN0IGRybV9yb2NrY2hpcF9yZ2FfZ2V0X3ZlciAqdmVyID0gZGF0YTsKKwlzdHJ1 Y3Qgcm9ja2NoaXBfcmdhICpyZ2E7CisJc3RydWN0IGRldmljZSAqZGV2OworCisJaWYgKCFyZ2Ff cHJpdikKKwkJcmV0dXJuIC1FTk9ERVY7CisKKwlkZXYgPSByZ2FfcHJpdi0+ZGV2OworCWlmICgh ZGV2KQorCQlyZXR1cm4gLUVOT0RFVjsKKworCXJnYSA9IGRldl9nZXRfZHJ2ZGF0YShkZXYpOwor CWlmICghcmdhKQorCQlyZXR1cm4gLUVGQVVMVDsKKworCXZlci0+bWFqb3IgPSByZ2EtPnZlcnNp b24ubWFqb3I7CisJdmVyLT5taW5vciA9IHJnYS0+dmVyc2lvbi5taW5vcjsKKworCXJldHVybiAw OworfQorCisvKgorICogSU9DUkwgZnVuY3Rpb25zIGZvciB1c2Vyc3BhY2UgdG8gc2VuZCBhbiBS R0EgcmVxdWVzdC4KKyAqLworaW50IHJvY2tjaGlwX3JnYV9zZXRfY21kbGlzdF9pb2N0bChzdHJ1 Y3QgZHJtX2RldmljZSAqZHJtX2Rldiwgdm9pZCAqZGF0YSwKKwkJCQkgICBzdHJ1Y3QgZHJtX2Zp bGUgKmZpbGUpCit7CisJc3RydWN0IHJvY2tjaGlwX2RybV9maWxlX3ByaXZhdGUgKmZpbGVfcHJp diA9IGZpbGUtPmRyaXZlcl9wcml2OworCXN0cnVjdCByb2NrY2hpcF9kcm1fcmdhX3ByaXZhdGUg KnJnYV9wcml2ID0gZmlsZV9wcml2LT5yZ2FfcHJpdjsKKwlzdHJ1Y3QgZHJtX3JvY2tjaGlwX3Jn YV9zZXRfY21kbGlzdCAqcmVxID0gZGF0YTsKKwlzdHJ1Y3QgcmdhX2NtZGxpc3Rfbm9kZSAqbm9k ZTsKKwlzdHJ1Y3QgcmdhX2NtZGxpc3QgKmNtZGxpc3Q7CisJc3RydWN0IHJvY2tjaGlwX3JnYSAq cmdhOworCWludCByZXQ7CisKKwlpZiAoIXJnYV9wcml2KQorCQlyZXR1cm4gLUVOT0RFVjsKKwor CWlmICghcmdhX3ByaXYtPmRldikKKwkJcmV0dXJuIC1FTk9ERVY7CisKKwlyZ2EgPSBkZXZfZ2V0 X2RydmRhdGEocmdhX3ByaXYtPmRldik7CisJaWYgKCFyZ2EpCisJCXJldHVybiAtRUZBVUxUOwor CisJbm9kZSA9IHJnYV9nZXRfY21kbGlzdChyZ2EpOworCWlmICghbm9kZSkKKwkJcmV0dXJuIC1F Tk9NRU07CisKKwljbWRsaXN0ID0gJm5vZGUtPmNtZGxpc3Q7CisJY21kbGlzdC0+bGFzdCA9IDA7 CisKKwlpZiAocmVxLT5jbWRfbnIgPiBSR0FfQ01ETElTVF9TSVpFIHx8IHJlcS0+Y21kX2J1Zl9u ciA+IFJHQV9DTURCVUZfU0laRSkgeworCQlkZXZfZXJyKHJnYS0+ZGV2LCAiY21kbGlzdCBzaXpl IGlzIHRvbyBiaWdcbiIpOworCQlyZXR1cm4gLUVJTlZBTDsKKwl9CisKKwkvKgorCSAqIENvcHkg dGhlIGNvbW1hbmQgLyBidWZmZXIgcmVnaXN0ZXJzIHNldHRpbmcgZnJvbSB1c2Vyc3BhY2UsIGVh Y2gKKwkgKiBjb21tYW5kIGhhdmUgdHdvIGludGVnZXIsIG9uZSBmb3IgcmVnaXN0ZXIgb2Zmc2V0 LCBhbm90aGVyIGZvcgorCSAqIHJlZ2lzdGVyIHZhbHVlLgorCSAqLworCWlmIChjb3B5X2Zyb21f dXNlcigodm9pZCAqKWNtZGxpc3QtPmRhdGEsIChjb25zdCB2b2lkIF9fdXNlciAqKXJlcS0+Y21k LAorCQkJICAgc2l6ZW9mKHN0cnVjdCBkcm1fcm9ja2NoaXBfcmdhX2NtZCkgKiByZXEtPmNtZF9u cikpCisJCXJldHVybiAtRUZBVUxUOworCWNtZGxpc3QtPmxhc3QgKz0gcmVxLT5jbWRfbnIgKiAy OworCisJaWYgKGNvcHlfZnJvbV91c2VyKCh2b2lkICopY21kbGlzdC0+ZGF0YSArIGNtZGxpc3Qt Pmxhc3QsCisJCQkgICAoY29uc3Qgdm9pZCBfX3VzZXIgKilyZXEtPmNtZF9idWYsCisJCQkgICBz aXplb2Yoc3RydWN0IGRybV9yb2NrY2hpcF9yZ2FfY21kKSAqIHJlcS0+Y21kX2J1Zl9ucikpCisJ CXJldHVybiAtRUZBVUxUOworCWNtZGxpc3QtPmxhc3QgKz0gcmVxLT5jbWRfYnVmX25yICogMjsK KworCS8qCisJICogQ2hlY2sgdGhlIHVzZXJzcGFjZSBjb21tYW5kIHJlZ2lzdGVycywgYW5kIG1h cHBpbmcgdGhlIGZyYW1lYnVmZmVyLAorCSAqIGNyZWF0ZSB0aGUgUkdBIG1tdSBwYWdlcyBvciBn ZXQgdGhlIGZyYW1lYnVmZmVyIGRtYSBhZGRyZXNzLgorCSAqLworCXJldCA9IHJnYV9jaGVja19y ZWdfb2Zmc2V0KHJnYS0+ZGV2LCBub2RlKTsKKwlpZiAocmV0IDwgMCkKKwkJcmV0dXJuIHJldDsK KworCXJldCA9IHJnYV9tYXBfY21kbGlzdF9nZW0ocmdhLCBub2RlLCBkcm1fZGV2LCBmaWxlKTsK KwlpZiAocmV0IDwgMCkKKwkJcmV0dXJuIHJldDsKKworCXJnYV9hZGRfY21kbGlzdF90b19pbnVz ZShyZ2FfcHJpdiwgbm9kZSk7CisKKwlyZXR1cm4gMDsKK30KKworLyoKKyAqIElPQ1JMIGZ1bmN0 aW9ucyBmb3IgdXNlcnNwYWNlIHRvIHN0YXJ0IFJHQSB0cmFuc2Zvcm0uCisgKi8KK2ludCByb2Nr Y2hpcF9yZ2FfZXhlY19pb2N0bChzdHJ1Y3QgZHJtX2RldmljZSAqZHJtX2Rldiwgdm9pZCAqZGF0 YSwKKwkJCSAgICBzdHJ1Y3QgZHJtX2ZpbGUgKmZpbGUpCit7CisJc3RydWN0IHJvY2tjaGlwX2Ry bV9maWxlX3ByaXZhdGUgKmZpbGVfcHJpdiA9IGZpbGUtPmRyaXZlcl9wcml2OworCXN0cnVjdCBy b2NrY2hpcF9kcm1fcmdhX3ByaXZhdGUgKnJnYV9wcml2ID0gZmlsZV9wcml2LT5yZ2FfcHJpdjsK KwlzdHJ1Y3QgcmdhX3J1bnF1ZXVlX25vZGUgKnJ1bnF1ZXVlOworCXN0cnVjdCByb2NrY2hpcF9y Z2EgKnJnYTsKKwlzdHJ1Y3QgZGV2aWNlICpkZXY7CisJaW50IHJldDsKKworCWlmICghcmdhX3By aXYpCisJCXJldHVybiAtRU5PREVWOworCisJZGV2ID0gcmdhX3ByaXYtPmRldjsKKwlpZiAoIWRl dikKKwkJcmV0dXJuIC1FTk9ERVY7CisKKwlyZ2EgPSBkZXZfZ2V0X2RydmRhdGEoZGV2KTsKKwlp ZiAoIXJnYSkKKwkJcmV0dXJuIC1FRkFVTFQ7CisKKwlydW5xdWV1ZSA9IGttZW1fY2FjaGVfYWxs b2MocmdhLT5ydW5xdWV1ZV9zbGFiLCBHRlBfS0VSTkVMKTsKKwlpZiAoIXJ1bnF1ZXVlKSB7CisJ CWRldl9lcnIocmdhLT5kZXYsICJmYWlsZWQgdG8gYWxsb2NhdGUgbWVtb3J5XG4iKTsKKwkJcmV0 dXJuIC1FTk9NRU07CisJfQorCisJcnVucXVldWUtPmRldiA9IHJnYS0+ZGV2OworCisJaW5pdF9j b21wbGV0aW9uKCZydW5xdWV1ZS0+Y29tcGxldGUpOworCisJSU5JVF9MSVNUX0hFQUQoJnJ1bnF1 ZXVlLT5ydW5fY21kbGlzdCk7CisKKwlsaXN0X3NwbGljZV9pbml0KCZyZ2FfcHJpdi0+aW51c2Vf Y21kbGlzdCwgJnJ1bnF1ZXVlLT5ydW5fY21kbGlzdCk7CisKKwlpZiAobGlzdF9lbXB0eSgmcnVu cXVldWUtPnJ1bl9jbWRsaXN0KSkgeworCQlkZXZfZXJyKHJnYS0+ZGV2LCAidGhlcmUgaXMgbm8g aW51c2UgY21kbGlzdFxuIik7CisJCWttZW1fY2FjaGVfZnJlZShyZ2EtPnJ1bnF1ZXVlX3NsYWIs IHJ1bnF1ZXVlKTsKKwkJcmV0dXJuIC1FUEVSTTsKKwl9CisKKwlyZXQgPSByZ2FfYWxsb2NfZG1h X2J1Zl9mb3JfY21kbGlzdChydW5xdWV1ZSk7CisJaWYgKHJldCA8IDApIHsKKwkJZGV2X2Vycihy Z2EtPmRldiwgImNtZGxpc3QgaW5pdCBmYWlsZWRcbiIpOworCQlyZXR1cm4gcmV0OworCX0KKwor CW11dGV4X2xvY2soJnJnYS0+cnVucXVldWVfbXV0ZXgpOworCXJ1bnF1ZXVlLT5waWQgPSBjdXJy ZW50LT5waWQ7CisJcnVucXVldWUtPmZpbGUgPSBmaWxlOworCWxpc3RfYWRkX3RhaWwoJnJ1bnF1 ZXVlLT5saXN0LCAmcmdhLT5ydW5xdWV1ZV9saXN0KTsKKwlpZiAoIXJnYS0+cnVucXVldWVfbm9k ZSkKKwkJcmdhX2V4ZWNfcnVucXVldWUocmdhKTsKKwltdXRleF91bmxvY2soJnJnYS0+cnVucXVl dWVfbXV0ZXgpOworCisJd2FpdF9mb3JfY29tcGxldGlvbigmcnVucXVldWUtPmNvbXBsZXRlKTsK KwlyZ2FfZnJlZV9ydW5xdWV1ZV9ub2RlKHJnYSwgcnVucXVldWUpOworCisJcmV0dXJuIDA7Cit9 CisKK3N0YXRpYyBpbnQgcm9ja2NoaXBfcmdhX29wZW4oc3RydWN0IGRybV9kZXZpY2UgKmRybV9k ZXYsIHN0cnVjdCBkZXZpY2UgKmRldiwKKwkJCSAgICAgc3RydWN0IGRybV9maWxlICpmaWxlKQor eworCXN0cnVjdCByb2NrY2hpcF9kcm1fZmlsZV9wcml2YXRlICpmaWxlX3ByaXYgPSBmaWxlLT5k cml2ZXJfcHJpdjsKKwlzdHJ1Y3Qgcm9ja2NoaXBfZHJtX3JnYV9wcml2YXRlICpyZ2FfcHJpdjsK KworCXJnYV9wcml2ID0ga3phbGxvYyhzaXplb2YoKnJnYV9wcml2KSwgR0ZQX0tFUk5FTCk7CisJ aWYgKCFyZ2FfcHJpdikKKwkJcmV0dXJuIC1FTk9NRU07CisKKwlyZ2FfcHJpdi0+ZGV2ID0gZGV2 OworCWZpbGVfcHJpdi0+cmdhX3ByaXYgPSByZ2FfcHJpdjsKKworCUlOSVRfTElTVF9IRUFEKCZy Z2FfcHJpdi0+aW51c2VfY21kbGlzdCk7CisKKwlyZXR1cm4gMDsKK30KKworc3RhdGljIHZvaWQg cm9ja2NoaXBfcmdhX2Nsb3NlKHN0cnVjdCBkcm1fZGV2aWNlICpkcm1fZGV2LCBzdHJ1Y3QgZGV2 aWNlICpkZXYsCisJCQkgICAgICAgc3RydWN0IGRybV9maWxlICpmaWxlKQoreworCXN0cnVjdCBy b2NrY2hpcF9kcm1fZmlsZV9wcml2YXRlICpmaWxlX3ByaXYgPSBmaWxlLT5kcml2ZXJfcHJpdjsK KwlzdHJ1Y3Qgcm9ja2NoaXBfZHJtX3JnYV9wcml2YXRlICpyZ2FfcHJpdiA9IGZpbGVfcHJpdi0+ cmdhX3ByaXY7CisJc3RydWN0IHJnYV9jbWRsaXN0X25vZGUgKm5vZGUsICpuOworCXN0cnVjdCBy b2NrY2hpcF9yZ2EgKnJnYTsKKworCWlmICghZGV2KQorCQlyZXR1cm47CisKKwlyZ2EgPSBkZXZf Z2V0X2RydmRhdGEoZGV2KTsKKwlpZiAoIXJnYSkKKwkJcmV0dXJuOworCisJbXV0ZXhfbG9jaygm cmdhLT5jbWRsaXN0X211dGV4KTsKKwlsaXN0X2Zvcl9lYWNoX2VudHJ5X3NhZmUobm9kZSwgbiwg JnJnYV9wcml2LT5pbnVzZV9jbWRsaXN0LCBsaXN0KSB7CisJCS8qCisJCSAqIHVubWFwIGFsbCBn ZW0gb2JqZWN0cyBub3QgY29tcGxldGVkLgorCQkgKgorCQkgKiBQLlMuIGlmIGN1cnJlbnQgcHJv Y2VzcyB3YXMgdGVybWluYXRlZCBmb3JjZWx5IHRoZW4KKwkJICogdGhlcmUgbWF5IGJlIHNvbWUg Y29tbWFuZHMgaW4gaW51c2VfY21kbGlzdCBzbyB1bm1hcAorCQkgKiB0aGVtLgorCQkgKi8KKwkJ cmdhX3VubWFwX2NtZGxpc3RfZ2VtKHJnYSwgbm9kZSk7CisJCWxpc3RfbW92ZV90YWlsKCZub2Rl LT5saXN0LCAmcmdhLT5mcmVlX2NtZGxpc3QpOworCX0KKwltdXRleF91bmxvY2soJnJnYS0+Y21k bGlzdF9tdXRleCk7CisKKwlrZnJlZShmaWxlX3ByaXYtPnJnYV9wcml2KTsKK30KKworc3RhdGlj IHZvaWQgcmdhX3J1bnF1ZXVlX3dvcmtlcihzdHJ1Y3Qgd29ya19zdHJ1Y3QgKndvcmspCit7CisJ c3RydWN0IHJvY2tjaGlwX3JnYSAqcmdhID0gY29udGFpbmVyX29mKHdvcmssIHN0cnVjdCByb2Nr Y2hpcF9yZ2EsCisJCQkJCSAgICBydW5xdWV1ZV93b3JrKTsKKworCW11dGV4X2xvY2soJnJnYS0+ cnVucXVldWVfbXV0ZXgpOworCXBtX3J1bnRpbWVfcHV0X3N5bmMocmdhLT5kZXYpOworCisJY29t cGxldGUoJnJnYS0+cnVucXVldWVfbm9kZS0+Y29tcGxldGUpOworCisJaWYgKHJnYS0+c3VzcGVu ZGVkKQorCQlyZ2EtPnJ1bnF1ZXVlX25vZGUgPSBOVUxMOworCWVsc2UKKwkJcmdhX2V4ZWNfcnVu cXVldWUocmdhKTsKKworCW11dGV4X3VubG9jaygmcmdhLT5ydW5xdWV1ZV9tdXRleCk7Cit9CisK K3N0YXRpYyBpcnFyZXR1cm5fdCByZ2FfaXJxX2hhbmRsZXIoaW50IGlycSwgdm9pZCAqZGV2X2lk KQoreworCXN0cnVjdCByb2NrY2hpcF9yZ2EgKnJnYSA9IGRldl9pZDsKKwlpbnQgaW50cjsKKwor CWludHIgPSByZ2FfcmVhZChyZ2EsIFJHQV9JTlQpICYgMHhmOworCisJcmdhX21vZChyZ2EsIFJH QV9JTlQsIGludHIgPDwgNCwgMHhmIDw8IDQpOworCisJaWYgKGludHIgJiAweDA0KQorCQlxdWV1 ZV93b3JrKHJnYS0+cmdhX3dvcmtxLCAmcmdhLT5ydW5xdWV1ZV93b3JrKTsKKworCXJldHVybiBJ UlFfSEFORExFRDsKK30KKworc3RhdGljIGludCByZ2FfcGFyc2VfZHQoc3RydWN0IHJvY2tjaGlw X3JnYSAqcmdhKQoreworCXN0cnVjdCByZXNldF9jb250cm9sICpzY2xrX3JzdCwgKmFjbGtfcnN0 LCAqaGNsa19yc3Q7CisKKwlzY2xrX3JzdCA9IGRldm1fcmVzZXRfY29udHJvbF9nZXQocmdhLT5k ZXYsICJzY2xrIik7CisJaWYgKElTX0VSUihzY2xrX3JzdCkpIHsKKwkJZGV2X2VycihyZ2EtPmRl diwgImZhaWxlZCB0byBnZXQgc2NsayByZXNldCBjb250cm9sbGVyXG4iKTsKKwkJcmV0dXJuIFBU Ul9FUlIoc2Nsa19yc3QpOworCX0KKworCWFjbGtfcnN0ID0gZGV2bV9yZXNldF9jb250cm9sX2dl dChyZ2EtPmRldiwgImFjbGsiKTsKKwlpZiAoSVNfRVJSKGFjbGtfcnN0KSkgeworCQlkZXZfZXJy KHJnYS0+ZGV2LCAiZmFpbGVkIHRvIGdldCBhY2xrIHJlc2V0IGNvbnRyb2xsZXJcbiIpOworCQly ZXR1cm4gUFRSX0VSUihhY2xrX3JzdCk7CisJfQorCisJaGNsa19yc3QgPSBkZXZtX3Jlc2V0X2Nv bnRyb2xfZ2V0KHJnYS0+ZGV2LCAiaGNsayIpOworCWlmIChJU19FUlIoaGNsa19yc3QpKSB7CisJ CWRldl9lcnIocmdhLT5kZXYsICJmYWlsZWQgdG8gZ2V0IGhjbGsgcmVzZXQgY29udHJvbGxlclxu Iik7CisJCXJldHVybiBQVFJfRVJSKGhjbGtfcnN0KTsKKwl9CisKKwlyZXNldF9jb250cm9sX2Fz c2VydChzY2xrX3JzdCk7CisJdXNsZWVwX3JhbmdlKDEwLCAyMCk7CisJcmVzZXRfY29udHJvbF9k ZWFzc2VydChzY2xrX3JzdCk7CisKKwlyZXNldF9jb250cm9sX2Fzc2VydChhY2xrX3JzdCk7CisJ dXNsZWVwX3JhbmdlKDEwLCAyMCk7CisJcmVzZXRfY29udHJvbF9kZWFzc2VydChhY2xrX3JzdCk7 CisKKwlyZXNldF9jb250cm9sX2Fzc2VydChoY2xrX3JzdCk7CisJdXNsZWVwX3JhbmdlKDEwLCAy MCk7CisJcmVzZXRfY29udHJvbF9kZWFzc2VydChoY2xrX3JzdCk7CisKKwlyZ2EtPnNjbGsgPSBk ZXZtX2Nsa19nZXQocmdhLT5kZXYsICJzY2xrIik7CisJaWYgKElTX0VSUihyZ2EtPnNjbGspKSB7 CisJCWRldl9lcnIocmdhLT5kZXYsICJmYWlsZWQgdG8gZ2V0IHNjbGsgY2xvY2tcbiIpOworCQly ZXR1cm4gUFRSX0VSUihyZ2EtPnNjbGspOworCX0KKworCXJnYS0+YWNsayA9IGRldm1fY2xrX2dl dChyZ2EtPmRldiwgImFjbGsiKTsKKwlpZiAoSVNfRVJSKHJnYS0+YWNsaykpIHsKKwkJZGV2X2Vy cihyZ2EtPmRldiwgImZhaWxlZCB0byBnZXQgYWNsayBjbG9ja1xuIik7CisJCXJldHVybiBQVFJf RVJSKHJnYS0+YWNsayk7CisJfQorCisJcmdhLT5oY2xrID0gZGV2bV9jbGtfZ2V0KHJnYS0+ZGV2 LCAiaGNsayIpOworCWlmIChJU19FUlIocmdhLT5oY2xrKSkgeworCQlkZXZfZXJyKHJnYS0+ZGV2 LCAiZmFpbGVkIHRvIGdldCBoY2xrIGNsb2NrXG4iKTsKKwkJcmV0dXJuIFBUUl9FUlIocmdhLT5o Y2xrKTsKKwl9CisKKwlyZXR1cm4gcmdhX2VuYWJsZV9jbG9ja3MocmdhKTsKK30KKworc3RhdGlj IGNvbnN0IHN0cnVjdCBvZl9kZXZpY2VfaWQgcm9ja2NoaXBfcmdhX2R0X2lkc1tdID0geworCXsg LmNvbXBhdGlibGUgPSAicm9ja2NoaXAscmszMjg4LXJnYSIsIH0sCisJeyAuY29tcGF0aWJsZSA9 ICJyb2NrY2hpcCxyazMyMjgtcmdhIiwgfSwKKwl7IC5jb21wYXRpYmxlID0gInJvY2tjaGlwLHJr MzM5OS1yZ2EiLCB9LAorCXt9LAorfTsKK01PRFVMRV9ERVZJQ0VfVEFCTEUob2YsIHJvY2tjaGlw X3JnYV9kdF9pZHMpOworCitzdGF0aWMgaW50IHJnYV9wcm9iZShzdHJ1Y3QgcGxhdGZvcm1fZGV2 aWNlICpwZGV2KQoreworCXN0cnVjdCBkcm1fcm9ja2NoaXBfc3ViZHJ2ICpzdWJkcnY7CisJc3Ry dWN0IHJvY2tjaGlwX3JnYSAqcmdhOworCXN0cnVjdCByZXNvdXJjZSAqaW9yZXM7CisJaW50IGly cTsKKwlpbnQgcmV0OworCisJaWYgKCFwZGV2LT5kZXYub2Zfbm9kZSkKKwkJcmV0dXJuIC1FTk9E RVY7CisKKwlyZ2EgPSBkZXZtX2t6YWxsb2MoJnBkZXYtPmRldiwgc2l6ZW9mKCpyZ2EpLCBHRlBf S0VSTkVMKTsKKwlpZiAoIXJnYSkKKwkJcmV0dXJuIC1FTk9NRU07CisKKwlyZ2EtPmRldiA9ICZw ZGV2LT5kZXY7CisKKwlyZ2EtPnJ1bnF1ZXVlX3NsYWIgPSBrbWVtX2NhY2hlX2NyZWF0ZSgicmdh X3J1bnF1ZXVlX3NsYWIiLAorCQkJCQkgICAgICAgc2l6ZW9mKHN0cnVjdCByZ2FfcnVucXVldWVf bm9kZSksCisJCQkJCSAgICAgICAwLCAwLCBOVUxMKTsKKwlpZiAoIXJnYS0+cnVucXVldWVfc2xh YikKKwkJcmV0dXJuIC1FTk9NRU07CisKKwlyZ2EtPnJnYV93b3JrcSA9IGNyZWF0ZV9zaW5nbGV0 aHJlYWRfd29ya3F1ZXVlKCJyZ2EiKTsKKwlpZiAoIXJnYS0+cmdhX3dvcmtxKSB7CisJCWRldl9l cnIocmdhLT5kZXYsICJmYWlsZWQgdG8gY3JlYXRlIHdvcmtxdWV1ZVxuIik7CisJCWdvdG8gZXJy X2Rlc3Ryb3lfc2xhYjsKKwl9CisKKwlJTklUX1dPUksoJnJnYS0+cnVucXVldWVfd29yaywgcmdh X3J1bnF1ZXVlX3dvcmtlcik7CisJSU5JVF9MSVNUX0hFQUQoJnJnYS0+cnVucXVldWVfbGlzdCk7 CisJbXV0ZXhfaW5pdCgmcmdhLT5ydW5xdWV1ZV9tdXRleCk7CisKKwlJTklUX0xJU1RfSEVBRCgm cmdhLT5mcmVlX2NtZGxpc3QpOworCW11dGV4X2luaXQoJnJnYS0+Y21kbGlzdF9tdXRleCk7CisK KwlyZ2FfaW5pdF9jbWRsaXN0KHJnYSk7CisKKwlyZXQgPSByZ2FfcGFyc2VfZHQocmdhKTsKKwlp ZiAocmV0KSB7CisJCWRldl9lcnIocmdhLT5kZXYsICJVbmFibGUgdG8gcGFyc2UgT0YgZGF0YVxu Iik7CisJCWdvdG8gZXJyX2Rlc3Ryb3lfd29ya3F1ZXVlOworCX0KKworCXBtX3J1bnRpbWVfZW5h YmxlKHJnYS0+ZGV2KTsKKworCWlvcmVzID0gcGxhdGZvcm1fZ2V0X3Jlc291cmNlKHBkZXYsIElP UkVTT1VSQ0VfTUVNLCAwKTsKKworCXJnYS0+cmVncyA9IGRldm1faW9yZW1hcF9yZXNvdXJjZShy Z2EtPmRldiwgaW9yZXMpOworCWlmIChJU19FUlIocmdhLT5yZWdzKSkgeworCQlyZXQgPSBQVFJf RVJSKHJnYS0+cmVncyk7CisJCWdvdG8gZXJyX3B1dF9jbGs7CisJfQorCisJaXJxID0gcGxhdGZv cm1fZ2V0X2lycShwZGV2LCAwKTsKKwlpZiAoaXJxIDwgMCkgeworCQlkZXZfZXJyKHJnYS0+ZGV2 LCAiZmFpbGVkIHRvIGdldCBpcnFcbiIpOworCQlyZXQgPSBpcnE7CisJCWdvdG8gZXJyX3B1dF9j bGs7CisJfQorCisJcmV0ID0gZGV2bV9yZXF1ZXN0X2lycShyZ2EtPmRldiwgaXJxLCByZ2FfaXJx X2hhbmRsZXIsIDAsCisJCQkgICAgICAgZGV2X25hbWUocmdhLT5kZXYpLCByZ2EpOworCWlmIChy ZXQgPCAwKSB7CisJCWRldl9lcnIocmdhLT5kZXYsICJmYWlsZWQgdG8gcmVxdWVzdCBpcnFcbiIp OworCQlnb3RvIGVycl9wdXRfY2xrOworCX0KKworCXBsYXRmb3JtX3NldF9kcnZkYXRhKHBkZXYs IHJnYSk7CisKKwlyZ2EtPnZlcnNpb24ubWFqb3IgPSAocmdhX3JlYWQocmdhLCBSR0FfVkVSU0lP Tl9JTkZPKSA+PiAyNCkgJiAweEZGOworCXJnYS0+dmVyc2lvbi5taW5vciA9IChyZ2FfcmVhZChy Z2EsIFJHQV9WRVJTSU9OX0lORk8pID4+IDIwKSAmIDB4MEY7CisKKwlzdWJkcnYgPSAmcmdhLT5z dWJkcnY7CisJc3ViZHJ2LT5kZXYgPSByZ2EtPmRldjsKKwlzdWJkcnYtPm9wZW4gPSByb2NrY2hp cF9yZ2Ffb3BlbjsKKwlzdWJkcnYtPmNsb3NlID0gcm9ja2NoaXBfcmdhX2Nsb3NlOworCisJcm9j a2NoaXBfcmVnaXN0ZXJfc3ViZHJ2KHN1YmRydik7CisKKwlyZXR1cm4gMDsKKworZXJyX3B1dF9j bGs6CisJcG1fcnVudGltZV9kaXNhYmxlKHJnYS0+ZGV2KTsKK2Vycl9kZXN0cm95X3dvcmtxdWV1 ZToKKwlkZXN0cm95X3dvcmtxdWV1ZShyZ2EtPnJnYV93b3JrcSk7CitlcnJfZGVzdHJveV9zbGFi OgorCWttZW1fY2FjaGVfZGVzdHJveShyZ2EtPnJ1bnF1ZXVlX3NsYWIpOworCisJcmV0dXJuIHJl dDsKK30KKworc3RhdGljIGludCByZ2FfcmVtb3ZlKHN0cnVjdCBwbGF0Zm9ybV9kZXZpY2UgKnBk ZXYpCit7CisJc3RydWN0IHJvY2tjaGlwX3JnYSAqcmdhID0gcGxhdGZvcm1fZ2V0X2RydmRhdGEo cGRldik7CisKKwljYW5jZWxfd29ya19zeW5jKCZyZ2EtPnJ1bnF1ZXVlX3dvcmspOworCisJd2hp bGUgKHJnYS0+cnVucXVldWVfbm9kZSkgeworCQlyZ2FfZnJlZV9ydW5xdWV1ZV9ub2RlKHJnYSwg cmdhLT5ydW5xdWV1ZV9ub2RlKTsKKwkJcmdhLT5ydW5xdWV1ZV9ub2RlID0gcmdhX2dldF9ydW5x dWV1ZShyZ2EpOworCX0KKworCXJvY2tjaGlwX3VucmVnaXN0ZXJfc3ViZHJ2KCZyZ2EtPnN1YmRy dik7CisKKwlyZXR1cm4gMDsKK30KKworc3RhdGljIGludCByZ2Ffc3VzcGVuZChzdHJ1Y3QgZGV2 aWNlICpkZXYpCit7CisJc3RydWN0IHJvY2tjaGlwX3JnYSAqcmdhID0gZGV2X2dldF9kcnZkYXRh KGRldik7CisKKwltdXRleF9sb2NrKCZyZ2EtPnJ1bnF1ZXVlX211dGV4KTsKKwlyZ2EtPnN1c3Bl bmRlZCA9IHRydWU7CisJbXV0ZXhfdW5sb2NrKCZyZ2EtPnJ1bnF1ZXVlX211dGV4KTsKKworCWZs dXNoX3dvcmsoJnJnYS0+cnVucXVldWVfd29yayk7CisKKwlyZXR1cm4gMDsKK30KKworc3RhdGlj IGludCByZ2FfcmVzdW1lKHN0cnVjdCBkZXZpY2UgKmRldikKK3sKKwlzdHJ1Y3Qgcm9ja2NoaXBf cmdhICpyZ2EgPSBkZXZfZ2V0X2RydmRhdGEoZGV2KTsKKworCXJnYS0+c3VzcGVuZGVkID0gZmFs c2U7CisJcmdhX2V4ZWNfcnVucXVldWUocmdhKTsKKworCXJldHVybiAwOworfQorCisjaWZkZWYg Q09ORklHX1BNCitzdGF0aWMgaW50IHJnYV9ydW50aW1lX3N1c3BlbmQoc3RydWN0IGRldmljZSAq ZGV2KQoreworCXN0cnVjdCByb2NrY2hpcF9yZ2EgKnJnYSA9IGRldl9nZXRfZHJ2ZGF0YShkZXYp OworCisJcmdhX2Rpc2FibGVfY2xvY2tzKHJnYSk7CisKKwlyZXR1cm4gMDsKK30KKworc3RhdGlj IGludCByZ2FfcnVudGltZV9yZXN1bWUoc3RydWN0IGRldmljZSAqZGV2KQoreworCXN0cnVjdCBy b2NrY2hpcF9yZ2EgKnJnYSA9IGRldl9nZXRfZHJ2ZGF0YShkZXYpOworCisJcmV0dXJuIHJnYV9l bmFibGVfY2xvY2tzKHJnYSk7Cit9CisjZW5kaWYKKworc3RhdGljIGNvbnN0IHN0cnVjdCBkZXZf cG1fb3BzIHJnYV9wbSA9IHsKKwlTRVRfU1lTVEVNX1NMRUVQX1BNX09QUyhyZ2Ffc3VzcGVuZCwg cmdhX3Jlc3VtZSkKKwlTRVRfUlVOVElNRV9QTV9PUFMocmdhX3J1bnRpbWVfc3VzcGVuZCwKKwkJ CSAgIHJnYV9ydW50aW1lX3Jlc3VtZSwgTlVMTCkKK307CisKK3N0YXRpYyBzdHJ1Y3QgcGxhdGZv cm1fZHJpdmVyIHJnYV9wbHRmbV9kcml2ZXIgPSB7CisJLnByb2JlICA9IHJnYV9wcm9iZSwKKwku cmVtb3ZlID0gcmdhX3JlbW92ZSwKKwkuZHJpdmVyID0geworCQkubmFtZSA9ICJyb2NrY2hpcC1y Z2EiLAorCQkucG0gPSAmcmdhX3BtLAorCQkub2ZfbWF0Y2hfdGFibGUgPSByb2NrY2hpcF9yZ2Ff ZHRfaWRzLAorCX0sCit9OworCittb2R1bGVfcGxhdGZvcm1fZHJpdmVyKHJnYV9wbHRmbV9kcml2 ZXIpOworCitNT0RVTEVfQVVUSE9SKCJZYWtpciBZYW5nIDx5a2tAcm9jay1jaGlwcy5jb20+Iik7 CitNT0RVTEVfREVTQ1JJUFRJT04oIlJvY2tjaGlwIFJHQSBEcml2ZXIgRXh0ZW5zaW9uIik7CitN T0RVTEVfTElDRU5TRSgiR1BMIHYyIik7CitNT0RVTEVfQUxJQVMoInBsYXRmb3JtOnJvY2tjaGlw LXJnYSIpOwpkaWZmIC0tZ2l0IGEvZHJpdmVycy9ncHUvZHJtL3JvY2tjaGlwL3JvY2tjaGlwX2Ry bV9yZ2EuaCBiL2RyaXZlcnMvZ3B1L2RybS9yb2NrY2hpcC9yb2NrY2hpcF9kcm1fcmdhLmgKbmV3 IGZpbGUgbW9kZSAxMDA2NDQKaW5kZXggMDAwMDAwMC4uNGE4ODM5YQotLS0gL2Rldi9udWxsCisr KyBiL2RyaXZlcnMvZ3B1L2RybS9yb2NrY2hpcC9yb2NrY2hpcF9kcm1fcmdhLmgKQEAgLTAsMCAr MSwxMDggQEAKKyNpZm5kZWYgX19ST0NLQ0hJUF9EUk1fUkdBX18KKyNkZWZpbmUgX19ST0NLQ0hJ UF9EUk1fUkdBX18KKworI2RlZmluZSBSR0FfQ01EQlVGX1NJWkUJCQkxNAorI2RlZmluZSBSR0Ff Q01ETElTVF9TSVpFCQkweDIwCisjZGVmaW5lIFJHQV9DTURMSVNUX05VTQkJCTY0CisKKy8qIGNt ZGxpc3QgZGF0YSBzdHJ1Y3R1cmUgKi8KK3N0cnVjdCByZ2FfY21kbGlzdCB7CisJdTMyCQloZWFk OworCXVuc2lnbmVkIGxvbmcJZGF0YVtSR0FfQ01ETElTVF9TSVpFICogMl07CisJdTMyCQlsYXN0 OwkvKiBsYXN0IGRhdGEgb2Zmc2V0ICovCisJdm9pZAkJKnNyY19tbXVfcGFnZXM7CisJdm9pZAkJ KmRzdF9tbXVfcGFnZXM7CisJdm9pZAkJKnNyYzFfbW11X3BhZ2VzOworCXN0cnVjdCBkbWFfYnVm X2F0dGFjaG1lbnQgKnNyY19hdHRhY2g7CisJc3RydWN0IGRtYV9idWZfYXR0YWNobWVudCAqZHN0 X2F0dGFjaDsKK307CisKK3N0cnVjdCByZ2FfY21kbGlzdF9ub2RlIHsKKwlzdHJ1Y3QgbGlzdF9o ZWFkCWxpc3Q7CisJc3RydWN0IHJnYV9jbWRsaXN0CWNtZGxpc3Q7Cit9OworCitzdHJ1Y3Qgcmdh X3J1bnF1ZXVlX25vZGUgeworCXN0cnVjdCBsaXN0X2hlYWQJbGlzdDsKKworCXN0cnVjdCBkZXZp Y2UJCSpkZXY7CisJcGlkX3QJCQlwaWQ7CisJc3RydWN0IGRybV9maWxlCQkqZmlsZTsKKwlzdHJ1 Y3QgY29tcGxldGlvbgljb21wbGV0ZTsKKworCXN0cnVjdCBsaXN0X2hlYWQJcnVuX2NtZGxpc3Q7 CisKKwlpbnQJCQljbWRsaXN0X2NudDsKKwl2b2lkCQkJKmNtZGxpc3RfcG9vbF92aXJ0OworCWRt YV9hZGRyX3QJCWNtZGxpc3RfcG9vbDsKKwlzdHJ1Y3QgZG1hX2F0dHJzCWNtZGxpc3RfZG1hX2F0 dHJzOworfTsKKworc3RydWN0IHJvY2tjaGlwX3JnYV92ZXJzaW9uIHsKKwlfX3UzMgkJCW1ham9y OworCV9fdTMyCQkJbWlub3I7Cit9OworCitzdHJ1Y3Qgcm9ja2NoaXBfcmdhIHsKKwlzdHJ1Y3Qg ZHJtX2RldmljZQkqZHJtX2RldjsKKwlzdHJ1Y3QgZGV2aWNlCQkqZGV2OworCXN0cnVjdCByZWdt YXAJCSpncmY7CisJdm9pZCBfX2lvbWVtCQkqcmVnczsKKwlzdHJ1Y3QgY2xrCQkqc2NsazsKKwlz dHJ1Y3QgY2xrCQkqYWNsazsKKwlzdHJ1Y3QgY2xrCQkqaGNsazsKKworCWJvb2wJCQkJc3VzcGVu ZGVkOworCXN0cnVjdCByb2NrY2hpcF9yZ2FfdmVyc2lvbgl2ZXJzaW9uOworCXN0cnVjdCBkcm1f cm9ja2NoaXBfc3ViZHJ2CXN1YmRydjsKKwlzdHJ1Y3Qgd29ya3F1ZXVlX3N0cnVjdAkJKnJnYV93 b3JrcTsKKwlzdHJ1Y3Qgd29ya19zdHJ1Y3QJCXJ1bnF1ZXVlX3dvcms7CisKKwkvKiByZ2EgY29t bWFuZCBsaXN0IHBvb2wgKi8KKwlzdHJ1Y3QgcmdhX2NtZGxpc3Rfbm9kZQkJY21kbGlzdF9ub2Rl W1JHQV9DTURMSVNUX05VTV07CisJc3RydWN0IG11dGV4CQkJY21kbGlzdF9tdXRleDsKKworCXN0 cnVjdCBsaXN0X2hlYWQJCWZyZWVfY21kbGlzdDsKKworCS8qIHJnYSBydW5xdWV1ZSAqLworCXN0 cnVjdCByZ2FfcnVucXVldWVfbm9kZQkqcnVucXVldWVfbm9kZTsKKwlzdHJ1Y3QgbGlzdF9oZWFk CQlydW5xdWV1ZV9saXN0OworCXN0cnVjdCBtdXRleAkJCXJ1bnF1ZXVlX211dGV4OworCXN0cnVj dCBrbWVtX2NhY2hlCQkqcnVucXVldWVfc2xhYjsKK307CisKK3N0cnVjdCByb2NrY2hpcF9kcm1f cmdhX3ByaXZhdGUgeworCXN0cnVjdCBkZXZpY2UJCSpkZXY7CisJc3RydWN0IGxpc3RfaGVhZAlp bnVzZV9jbWRsaXN0OworCXN0cnVjdCBsaXN0X2hlYWQJdXNlcnB0cl9saXN0OworfTsKKworI2lm ZGVmIENPTkZJR19ST0NLQ0hJUF9EUk1fUkdBCitpbnQgcm9ja2NoaXBfcmdhX2dldF92ZXJfaW9j dGwoc3RydWN0IGRybV9kZXZpY2UgKmRldiwgdm9pZCAqZGF0YSwKKwkJCSAgICAgICBzdHJ1Y3Qg ZHJtX2ZpbGUgKmZpbGVfcHJpdik7CitpbnQgcm9ja2NoaXBfcmdhX3NldF9jbWRsaXN0X2lvY3Rs KHN0cnVjdCBkcm1fZGV2aWNlICpkZXYsIHZvaWQgKmRhdGEsCisJCQkJICAgc3RydWN0IGRybV9m aWxlICpmaWxlX3ByaXYpOworaW50IHJvY2tjaGlwX3JnYV9leGVjX2lvY3RsKHN0cnVjdCBkcm1f ZGV2aWNlICpkZXYsIHZvaWQgKmRhdGEsCisJCQkgICAgc3RydWN0IGRybV9maWxlICpmaWxlX3By aXYpOworI2Vsc2UKK3N0YXRpYyBpbmxpbmUgaW50IHJvY2tjaGlwX3JnYV9nZXRfdmVyX2lvY3Rs KHN0cnVjdCBkcm1fZGV2aWNlICpkZXYsIHZvaWQgKmRhdGEsCisJCQkJCSAgICAgc3RydWN0IGRy bV9maWxlICpmaWxlX3ByaXYpCit7CisJcmV0dXJuIC1FTk9ERVY7Cit9CisKK3N0YXRpYyBpbmxp bmUgaW50IHJvY2tjaGlwX3JnYV9zZXRfY21kbGlzdF9pb2N0bChzdHJ1Y3QgZHJtX2RldmljZSAq ZGV2LAorCQkJCQkJIHZvaWQgKmRhdGEsCisJCQkJCQkgc3RydWN0IGRybV9maWxlICpmaWxlX3By aXYpCit7CisJcmV0dXJuIC1FTk9ERVY7Cit9CisKK3N0YXRpYyBpbmxpbmUgaW50IHJvY2tjaGlw X3JnYV9leGVjX2lvY3RsKHN0cnVjdCBkcm1fZGV2aWNlICpkZXYsIHZvaWQgKmRhdGEsCisJCQkJ CSAgc3RydWN0IGRybV9maWxlICpmaWxlX3ByaXYpCit7CisJcmV0dXJuIC1FTk9ERVY7Cit9Cisj ZW5kaWYKKworI2VuZGlmIC8qIF9fUk9DS0NISVBfRFJNX1JHQV9fICovCmRpZmYgLS1naXQgYS9p bmNsdWRlL3VhcGkvZHJtL3JvY2tjaGlwX2RybS5oIGIvaW5jbHVkZS91YXBpL2RybS9yb2NrY2hp cF9kcm0uaApuZXcgZmlsZSBtb2RlIDEwMDY0NAppbmRleCAwMDAwMDAwLi4yZTNlMjQwCi0tLSAv ZGV2L251bGwKKysrIGIvaW5jbHVkZS91YXBpL2RybS9yb2NrY2hpcF9kcm0uaApAQCAtMCwwICsx LDYzIEBACisvKiByb2NrY2hpcF9kcm0uaAorICoKKyAqIENvcHlyaWdodCAoYykgMjAxNiBGdXpo b3UgUm9ja2NoaXAgRWxlY3Ryb25pY3MgQ28uLCBMdGQuCisgKiBBdXRob3JzOgorICoJWWFraXIg WWFuZyA8eWtrQHJvY2stY2hpcHMuY29tPgorICoKKyAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNv ZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSAgaXQgYW5kL29yIG1vZGlmeSBpdAorICogdW5k ZXIgIHRoZSB0ZXJtcyBvZiAgdGhlIEdOVSBHZW5lcmFsICBQdWJsaWMgTGljZW5zZSBhcyBwdWJs aXNoZWQgYnkgdGhlCisgKiBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247ICBlaXRoZXIgdmVyc2lv biAyIG9mIHRoZSAgTGljZW5zZSwgb3IgKGF0IHlvdXIKKyAqIG9wdGlvbikgYW55IGxhdGVyIHZl cnNpb24uCisgKi8KKworI2lmbmRlZiBfVUFQSV9ST0NLQ0hJUF9EUk1fSF8KKyNkZWZpbmUgX1VB UElfUk9DS0NISVBfRFJNX0hfCisKKyNpbmNsdWRlIDxkcm0vZHJtLmg+CisKK3N0cnVjdCBkcm1f cm9ja2NoaXBfcmdhX2dldF92ZXIgeworCV9fdTMyICAgbWFqb3I7CisJX191MzIgICBtaW5vcjsK K307CisKK3N0cnVjdCBkcm1fcm9ja2NoaXBfcmdhX2NtZCB7CisJX191MzIgICBvZmZzZXQ7CisJ X191MzIgICBkYXRhOworfTsKKworZW51bSBkcm1fcm9ja2NoaXBfcmdhX2J1Zl90eXBlIHsKKwlS R0FfQlVGX1RZUEVfVVNFUlBUUiA9IDEgPDwgMzEsCisJUkdBX0JVRl9UWVBFX0dFTUZEICAgPSAx IDw8IDMwLAorfTsKKworc3RydWN0IGRybV9yb2NrY2hpcF9yZ2FfdXNlcnB0ciB7CisJdW5zaWdu ZWQgbG9uZyB1c2VycHRyOworCXVuc2lnbmVkIGxvbmcgc2l6ZTsKK307CisKK3N0cnVjdCBkcm1f cm9ja2NoaXBfcmdhX3NldF9jbWRsaXN0IHsKKwlfX3U2NAkJY21kOworCV9fdTY0CQljbWRfYnVm OworCV9fdTMyCQljbWRfbnI7CisJX191MzIJCWNtZF9idWZfbnI7CisJX191NjQJCXVzZXJfZGF0 YTsKK307CisKK3N0cnVjdCBkcm1fcm9ja2NoaXBfcmdhX2V4ZWMgeworCV9fdTY0CQlhc3luYzsK K307CisKKyNkZWZpbmUgRFJNX1JPQ0tDSElQX1JHQV9HRVRfVkVSCQkweDIwCisjZGVmaW5lIERS TV9ST0NLQ0hJUF9SR0FfU0VUX0NNRExJU1QJCTB4MjEKKyNkZWZpbmUgRFJNX1JPQ0tDSElQX1JH QV9FWEVDCQkJMHgyMgorCisjZGVmaW5lIERSTV9JT0NUTF9ST0NLQ0hJUF9SR0FfR0VUX1ZFUgkJ RFJNX0lPV1IoRFJNX0NPTU1BTkRfQkFTRSArIFwKKwlEUk1fUk9DS0NISVBfUkdBX0dFVF9WRVIs IHN0cnVjdCBkcm1fcm9ja2NoaXBfcmdhX2dldF92ZXIpCisKKyNkZWZpbmUgRFJNX0lPQ1RMX1JP Q0tDSElQX1JHQV9TRVRfQ01ETElTVAlEUk1fSU9XUihEUk1fQ09NTUFORF9CQVNFICsgXAorCURS TV9ST0NLQ0hJUF9SR0FfU0VUX0NNRExJU1QsIHN0cnVjdCBkcm1fcm9ja2NoaXBfcmdhX3NldF9j bWRsaXN0KQorCisjZGVmaW5lIERSTV9JT0NUTF9ST0NLQ0hJUF9SR0FfRVhFQwkJRFJNX0lPV1Io RFJNX0NPTU1BTkRfQkFTRSArIFwKKwlEUk1fUk9DS0NISVBfUkdBX0VYRUMsIHN0cnVjdCBkcm1f cm9ja2NoaXBfcmdhX2V4ZWMpCisKKyNlbmRpZiAvKiBfVUFQSV9ST0NLQ0hJUF9EUk1fSCAqLwot LSAKMS45LjEKCgpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19f XwpkcmktZGV2ZWwgbWFpbGluZyBsaXN0CmRyaS1kZXZlbEBsaXN0cy5mcmVlZGVza3RvcC5vcmcK aHR0cHM6Ly9saXN0cy5mcmVlZGVza3RvcC5vcmcvbWFpbG1hbi9saXN0aW5mby9kcmktZGV2ZWwK From mboxrd@z Thu Jan 1 00:00:00 1970 From: ykk@rock-chips.com (Yakir Yang) Date: Mon, 21 Mar 2016 17:40:06 +0800 Subject: [RFC PATCH v1 2/4] drm: rockchip: add RGA driver support In-Reply-To: <1458552518-25527-1-git-send-email-ykk@rock-chips.com> References: <1458552518-25527-1-git-send-email-ykk@rock-chips.com> Message-ID: <1458553206-26880-1-git-send-email-ykk@rock-chips.com> To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org Rockchip RGA is a separate 2D raster graphic acceleration unit. It accelerates 2D graphics operations, such as point/line drawing, image scaling, rotation, BitBLT, alpha blending and image blur/sharpness. The RGA driver is based on Exynos G2D driver, it is performed by two tasks simply. 1. Configures the rendering parameters, such as foreground color and coordinates data by setting the drawing context registers. 2. Start the rendering process by calling rga_exec() ioctl. The RGA supports DMA mode as host interface. User can make command list to reduce HOST(ARM) loads. The contents of The command list is setted to relevant registers of RGA by DMA. The command list is composed Header and command sets and Tail. - Header: The number of command set(4Bytes) - Command set: Register offset(4Bytes) + Register data(4Bytes) - Tail: Pointer of base address of the other command list(4Bytes) By Tail field, the G2D can process many command lists without halt at one go. The G2D has following the rendering pipeline. ---> Color Fill ---> | | --> DMA (read) ---> Src Bitmap Process ----> Alpha/ROP ---> Format convert ---> DMA (Write) | | ---> Dst Bitmap Process ---> And supports various operations from the rendering pipeline. - copy - fast solid color fill - rotation - flip - 4 operand raster operation(ROP4) - alpha blending - color key - dithering - etc User should make the command list to data and registers needed by operation to use. The Rockchip RGA driver only manages the command lists received from user. Some registers needs memory base address(physical address) of image. User doesn't know its physical address, so fills the gem handle of that memory than address to command sets, then RGA driver converts it to memory base address. We adds three ioctls for Rockchip RGA. - ioctls DRM_ROCKCHIP_RGA_GET_VER: get the RGA hardware version DRM_ROCKCHIP_RGA_SET_CMDLIST: set the command list from user to driver DRM_ROCKCHIP_RGA_EXEC: execute the command lists setted to driver Signed-off-by: Yakir Yang --- .../bindings/display/rockchip/rockchip-rga.txt | 36 + drivers/gpu/drm/rockchip/Kconfig | 9 + drivers/gpu/drm/rockchip/Makefile | 1 + drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 35 +- drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 4 + drivers/gpu/drm/rockchip/rockchip_drm_rga.c | 977 +++++++++++++++++++++ drivers/gpu/drm/rockchip/rockchip_drm_rga.h | 108 +++ include/uapi/drm/rockchip_drm.h | 63 ++ 8 files changed, 1232 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/display/rockchip/rockchip-rga.txt create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_rga.c create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_rga.h create mode 100644 include/uapi/drm/rockchip_drm.h diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-rga.txt b/Documentation/devicetree/bindings/display/rockchip/rockchip-rga.txt new file mode 100644 index 0000000..0c606cb --- /dev/null +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-rga.txt @@ -0,0 +1,36 @@ +device-tree bindings for rockchip 2D raster graphic acceleration controller (RGA) + +RGA is a separate 2D raster graphic acceleration unit. It accelerates 2D +graphics operations, such as point/line drawing, image scaling, rotation, +BitBLT, alpha blending and image blur/sharpness. + +Required properties: +- compatible: value should be one of the following + "rockchip,rk3228-rga"; + "rockchip,rk3288-rga"; + "rockchip,rk3399-rga"; + +- interrupts: RGA interrupt number. + +- clocks: phandle to RGA sclk/hclk/aclk clocks + +- clock-names: should be "aclk" "hclk" and "sclk" + +- resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names: should be "aclk" "hclk" and "sclk" + +Example: +SoC specific DT entry: + rga: rga at ff680000 { + compatible = "rockchip,rk3399-rga"; + reg = <0xff680000 0x10000>; + interrupts = ; + interrupt-names = "rga"; + clocks = <&cru ACLK_RGA>, <&cru HCLK_RGA>, <&cru SCLK_RGA>; + clock-names = "aclk", "hclk", "sclk"; + + resets = <&cru SRST_A_RGA>, <&cru SRST_H_RGA>, <&cru SRST_RGA_CORE>; + reset-names = "aclk", "hclk", "sclk"; + status = "disabled"; + }; diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index 76b3362..220221b 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -16,6 +16,15 @@ config DRM_ROCKCHIP 2D or 3D acceleration; acceleration is performed by other IP found on the SoC. +config ROCKCHIP_DRM_RGA + tristate "Rockchip RGA support" + depends on DRM_ROCKCHIP + help + Choose this option to enable support for Rockchip RGA. + Rockchip RGA is a kind of hardware 2D accelerator, and it support + solid roration, scaling, color format transform, say Y to enable its + driver + config ROCKCHIP_DW_HDMI tristate "Rockchip specific extensions for Synopsys DW HDMI" depends on DRM_ROCKCHIP diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index df8fbef..7de547c 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -9,5 +9,6 @@ rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o obj-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o obj-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o obj-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o +obj-$(CONFIG_ROCKCHIP_DRM_RGA) += rockchip_drm_rga.o obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o rockchip_vop_reg.o diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index 4e0feb2..1638bc9 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -25,10 +25,13 @@ #include #include +#include + #include "rockchip_drm_drv.h" #include "rockchip_drm_fb.h" #include "rockchip_drm_fbdev.h" #include "rockchip_drm_gem.h" +#include "rockchip_drm_rga.h" #define DRIVER_NAME "rockchip" #define DRIVER_DESC "RockChip Soc DRM" @@ -277,16 +280,28 @@ EXPORT_SYMBOL_GPL(rockchip_unregister_subdrv); static int rockchip_drm_open(struct drm_device *dev, struct drm_file *file) { + struct rockchip_drm_file_private *file_priv; struct drm_rockchip_subdrv *subdrv; int ret = 0; + file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL); + if (!file_priv) + return -ENOMEM; + + file->driver_priv = file_priv; + list_for_each_entry(subdrv, &rockchip_drm_subdrv_list, list) { ret = subdrv->open(dev, subdrv->dev, file); if (ret) - return ret; + goto err_file_priv_free; } return 0; + +err_file_priv_free: + kfree(file_priv); + file->driver_priv = NULL; + return ret; } static void rockchip_drm_preclose(struct drm_device *dev, @@ -298,6 +313,12 @@ static void rockchip_drm_preclose(struct drm_device *dev, subdrv->close(dev, subdrv->dev, file); } +static void rockchip_drm_postclose(struct drm_device *dev, + struct drm_file *file) +{ + kfree(file->driver_priv); +} + void rockchip_drm_lastclose(struct drm_device *dev) { struct rockchip_drm_private *priv = dev->dev_private; @@ -305,6 +326,15 @@ void rockchip_drm_lastclose(struct drm_device *dev) drm_fb_helper_restore_fbdev_mode_unlocked(&priv->fbdev_helper); } +static const struct drm_ioctl_desc rockchip_ioctls[] = { + DRM_IOCTL_DEF_DRV(ROCKCHIP_RGA_GET_VER, rockchip_rga_get_ver_ioctl, + DRM_AUTH | DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(ROCKCHIP_RGA_SET_CMDLIST, rockchip_rga_set_cmdlist_ioctl, + DRM_AUTH | DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(ROCKCHIP_RGA_EXEC, rockchip_rga_exec_ioctl, + DRM_AUTH | DRM_RENDER_ALLOW), +}; + static const struct file_operations rockchip_drm_driver_fops = { .owner = THIS_MODULE, .open = drm_open, @@ -330,6 +360,7 @@ static struct drm_driver rockchip_drm_driver = { .unload = rockchip_drm_unload, .open = rockchip_drm_open, .preclose = rockchip_drm_preclose, + .postclose = rockchip_drm_postclose, .lastclose = rockchip_drm_lastclose, .get_vblank_counter = drm_vblank_no_hw_counter, .enable_vblank = rockchip_drm_crtc_enable_vblank, @@ -347,6 +378,8 @@ static struct drm_driver rockchip_drm_driver = { .gem_prime_vmap = rockchip_gem_prime_vmap, .gem_prime_vunmap = rockchip_gem_prime_vunmap, .gem_prime_mmap = rockchip_gem_mmap_buf, + .ioctls = rockchip_ioctls, + .num_ioctls = ARRAY_SIZE(rockchip_ioctls), .fops = &rockchip_drm_driver_fops, .name = DRIVER_NAME, .desc = DRIVER_DESC, diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index 5ea5fcb..ea30ba6 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -53,6 +53,10 @@ struct drm_rockchip_subdrv { struct drm_file *file); }; +struct rockchip_drm_file_private { + struct rockchip_drm_rga_private *rga_priv; +}; + struct rockchip_atomic_commit { struct work_struct work; struct drm_atomic_state *state; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_rga.c b/drivers/gpu/drm/rockchip/rockchip_drm_rga.c new file mode 100644 index 0000000..4202121 --- /dev/null +++ b/drivers/gpu/drm/rockchip/rockchip_drm_rga.c @@ -0,0 +1,977 @@ +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: Yakir Yang + * + * based on exynos_drm_g2d.c + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "rockchip_drm_drv.h" +#include "rockchip_drm_rga.h" + +#define RGA_MODE_BASE_REG 0x0100 +#define RGA_MODE_MAX_REG 0x017C + +#define RGA_SYS_CTRL 0x0000 +#define RGA_CMD_CTRL 0x0004 +#define RGA_CMD_BASE 0x0008 +#define RGA_INT 0x0010 +#define RGA_MMU_CTRL0 0x0014 +#define RGA_VERSION_INFO 0x0028 + +#define RGA_SRC_Y_RGB_BASE_ADDR 0x0108 +#define RGA_SRC_CB_BASE_ADDR 0x010C +#define RGA_SRC_CR_BASE_ADDR 0x0110 +#define RGA_SRC1_RGB_BASE_ADDR 0x0114 +#define RGA_DST_Y_RGB_BASE_ADDR 0x013C +#define RGA_DST_CB_BASE_ADDR 0x0140 +#define RGA_DST_CR_BASE_ADDR 0x014C +#define RGA_MMU_CTRL1 0x016C +#define RGA_MMU_SRC_BASE 0x0170 +#define RGA_MMU_SRC1_BASE 0x0174 +#define RGA_MMU_DST_BASE 0x0178 + +static void rga_dma_flush_range(void *ptr, int size) +{ +#ifdef CONFIG_ARM + dmac_flush_range(ptr, ptr + size); + outer_flush_range(virt_to_phys(ptr), virt_to_phys(ptr + size)); +#elif CONFIG_ARM64 + __dma_flush_range(ptr, ptr + size); +#endif +} + +static inline void rga_write(struct rockchip_rga *rga, u32 reg, u32 value) +{ + writel(value, rga->regs + reg); +} + +static inline u32 rga_read(struct rockchip_rga *rga, u32 reg) +{ + return readl(rga->regs + reg); +} + +static inline void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask) +{ + u32 temp = rga_read(rga, reg) & ~(mask); + + temp |= val & mask; + rga_write(rga, reg, temp); +} + +static int rga_enable_clocks(struct rockchip_rga *rga) +{ + int ret; + + ret = clk_prepare_enable(rga->sclk); + if (ret) { + dev_err(rga->dev, "Cannot enable rga sclk: %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(rga->aclk); + if (ret) { + dev_err(rga->dev, "Cannot enable rga aclk: %d\n", ret); + goto err_disable_sclk; + } + + ret = clk_prepare_enable(rga->hclk); + if (ret) { + dev_err(rga->dev, "Cannot enable rga hclk: %d\n", ret); + goto err_disable_aclk; + } + + return 0; + +err_disable_sclk: + clk_disable_unprepare(rga->sclk); +err_disable_aclk: + clk_disable_unprepare(rga->aclk); + + return ret; +} + +static void rga_disable_clocks(struct rockchip_rga *rga) +{ + clk_disable_unprepare(rga->sclk); + clk_disable_unprepare(rga->hclk); + clk_disable_unprepare(rga->aclk); +} + +static void rga_init_cmdlist(struct rockchip_rga *rga) +{ + struct rga_cmdlist_node *node; + int nr; + + node = rga->cmdlist_node; + + for (nr = 0; nr < ARRAY_SIZE(rga->cmdlist_node); nr++) + list_add_tail(&node[nr].list, &rga->free_cmdlist); +} + +static int rga_alloc_dma_buf_for_cmdlist(struct rga_runqueue_node *runqueue) +{ + struct list_head *run_cmdlist = &runqueue->run_cmdlist; + struct device *dev = runqueue->dev; + struct dma_attrs cmdlist_dma_attrs; + struct rga_cmdlist_node *node; + void *cmdlist_pool_virt; + dma_addr_t cmdlist_pool; + int cmdlist_cnt = 0; + int count = 0; + + list_for_each_entry(node, run_cmdlist, list) + cmdlist_cnt++; + + init_dma_attrs(&cmdlist_dma_attrs); + dma_set_attr(DMA_ATTR_WRITE_COMBINE, &runqueue->cmdlist_dma_attrs); + + cmdlist_pool_virt = dma_alloc_attrs(dev, cmdlist_cnt * RGA_CMDLIST_SIZE, + &cmdlist_pool, GFP_KERNEL, + &cmdlist_dma_attrs); + if (!cmdlist_pool_virt) { + dev_err(dev, "failed to allocate cmdlist dma memory\n"); + return -ENOMEM; + } + + /* + * Fill in the RGA operation registers from cmdlist command buffer, + * and also filled in the MMU TLB base information. + */ + list_for_each_entry(node, run_cmdlist, list) { + struct rga_cmdlist *cmdlist = &node->cmdlist; + unsigned int mmu_ctrl = 0; + unsigned int *dest; + unsigned int reg; + int i; + + dest = cmdlist_pool_virt + RGA_CMDLIST_SIZE * 4 * count++; + + for (i = 0; i < cmdlist->last / 2; i++) { + reg = (node->cmdlist.data[2 * i] - RGA_MODE_BASE_REG); + if (reg > RGA_MODE_BASE_REG) + continue; + dest[reg << 2] = cmdlist->data[2 * i + 1]; + } + + if (cmdlist->src_mmu_pages) { + reg = RGA_MMU_SRC_BASE - RGA_MODE_BASE_REG; + dest[reg << 2] = virt_to_phys(cmdlist->src_mmu_pages) >> 4; + mmu_ctrl |= 0x7; + } + + if (cmdlist->dst_mmu_pages) { + reg = RGA_MMU_DST_BASE - RGA_MODE_BASE_REG; + dest[reg << 2] = virt_to_phys(cmdlist->dst_mmu_pages) >> 4; + mmu_ctrl |= 0x7 << 8; + } + + if (cmdlist->src1_mmu_pages) { + reg = RGA_MMU_SRC1_BASE - RGA_MODE_BASE_REG; + dest[reg << 2] = virt_to_phys(cmdlist->src1_mmu_pages) >> 4; + mmu_ctrl |= 0x7 << 4; + } + + reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG; + dest[reg << 2] = mmu_ctrl; + } + + rga_dma_flush_range(cmdlist_pool_virt, cmdlist_cnt * RGA_CMDLIST_SIZE); + + runqueue->cmdlist_dma_attrs = cmdlist_dma_attrs; + runqueue->cmdlist_pool_virt = cmdlist_pool_virt; + runqueue->cmdlist_pool = cmdlist_pool; + runqueue->cmdlist_cnt = cmdlist_cnt; + + return 0; +} + +static int rga_check_reg_offset(struct device *dev, + struct rga_cmdlist_node *node) +{ + struct rga_cmdlist *cmdlist = &node->cmdlist; + int index; + int reg; + int i; + + for (i = 0; i < cmdlist->last / 2; i++) { + index = cmdlist->last - 2 * (i + 1); + reg = cmdlist->data[index]; + + switch (reg) { + case RGA_BUF_TYPE_GEMFD | RGA_DST_Y_RGB_BASE_ADDR: + case RGA_BUF_TYPE_GEMFD | RGA_SRC_Y_RGB_BASE_ADDR: + break; + + case RGA_BUF_TYPE_USERPTR | RGA_DST_Y_RGB_BASE_ADDR: + case RGA_BUF_TYPE_USERPTR | RGA_SRC_Y_RGB_BASE_ADDR: + goto err; + + default: + if (reg < RGA_MODE_BASE_REG || reg > RGA_MODE_MAX_REG) + goto err; + + if (reg % 4) + goto err; + } + } + + return 0; + +err: + dev_err(dev, "Bad register offset: 0x%lx\n", cmdlist->data[index]); + return -EINVAL; +} + +static struct dma_buf_attachment * +rga_gem_buf_to_pages(struct rockchip_rga *rga, void **mmu_pages, int fd) +{ + struct dma_buf_attachment *attach; + struct dma_buf *dmabuf; + struct sg_table *sgt; + struct scatterlist *sgl; + unsigned int mapped_size = 0; + unsigned int address; + unsigned int len; + unsigned int i, p; + unsigned int *pages; + int ret; + + dmabuf = dma_buf_get(fd); + if (IS_ERR(dmabuf)) { + dev_err(rga->dev, "Failed to get dma_buf with fd %d\n", fd); + return ERR_PTR(-EINVAL); + } + + attach = dma_buf_attach(dmabuf, rga->dev); + if (IS_ERR(attach)) { + dev_err(rga->dev, "Failed to attach dma_buf\n"); + ret = PTR_ERR(attach); + goto failed_attach; + } + + sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); + if (IS_ERR(sgt)) { + dev_err(rga->dev, "Failed to map dma_buf attachment\n"); + ret = PTR_ERR(sgt); + goto failed_detach; + } + + /* + * Alloc (2^3 * 4K) = 32K byte for storing pages, those space could + * cover 32K * 4K = 128M ram address. + */ + pages = (unsigned int *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 3); + + for_each_sg(sgt->sgl, sgl, sgt->nents, i) { + len = sg_dma_len(sgl) >> PAGE_SHIFT; + address = sg_phys(sgl); + + for (p = 0; p < len; p++) { + dma_addr_t phys = address + (p << PAGE_SHIFT); + void *virt = phys_to_virt(phys); + + rga_dma_flush_range(virt, 4 * 1024); + pages[mapped_size + p] = phys; + } + + mapped_size += len; + } + + rga_dma_flush_range(pages, 32 * 1024); + + *mmu_pages = pages; + + dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL); + + return attach; + +failed_detach: + dma_buf_detach(dmabuf, attach); +failed_attach: + dma_buf_put(dmabuf); + + return ERR_PTR(ret); +} + +static int rga_map_cmdlist_gem(struct rockchip_rga *rga, + struct rga_cmdlist_node *node, + struct drm_device *drm_dev, + struct drm_file *file) +{ + struct rga_cmdlist *cmdlist = &node->cmdlist; + struct dma_buf_attachment *attach; + void *mmu_pages; + int fd; + int i; + + for (i = 0; i < cmdlist->last / 2; i++) { + int index = cmdlist->last - 2 * (i + 1); + + switch (cmdlist->data[index]) { + case RGA_SRC_Y_RGB_BASE_ADDR | RGA_BUF_TYPE_GEMFD: + fd = cmdlist->data[index + 1]; + attach = rga_gem_buf_to_pages(rga, &mmu_pages, fd); + + cmdlist->src_attach = attach; + cmdlist->src_mmu_pages = mmu_pages; + break; + + case RGA_DST_Y_RGB_BASE_ADDR | RGA_BUF_TYPE_GEMFD: + fd = cmdlist->data[index + 1]; + attach = rga_gem_buf_to_pages(rga, &mmu_pages, fd); + + cmdlist->dst_attach = attach; + cmdlist->dst_mmu_pages = mmu_pages; + break; + } + } + + return 0; +} + +static void rga_unmap_cmdlist_gem(struct rockchip_rga *rga, + struct rga_cmdlist_node *node) +{ + struct dma_buf_attachment *attach; + struct dma_buf *dma_buf; + + attach = node->cmdlist.src_attach; + if (attach) { + dma_buf = attach->dmabuf; + dma_buf_detach(dma_buf, attach); + dma_buf_put(dma_buf); + } + node->cmdlist.src_attach = NULL; + + attach = node->cmdlist.dst_attach; + if (attach) { + dma_buf = attach->dmabuf; + dma_buf_detach(dma_buf, attach); + dma_buf_put(dma_buf); + } + node->cmdlist.dst_attach = NULL; + + if (node->cmdlist.src_mmu_pages) + free_pages((unsigned long)node->cmdlist.src_mmu_pages, 3); + node->cmdlist.src_mmu_pages = NULL; + + if (node->cmdlist.src1_mmu_pages) + free_pages((unsigned long)node->cmdlist.src1_mmu_pages, 3); + node->cmdlist.src1_mmu_pages = NULL; + + if (node->cmdlist.dst_mmu_pages) + free_pages((unsigned long)node->cmdlist.dst_mmu_pages, 3); + node->cmdlist.dst_mmu_pages = NULL; +} + +static void rga_cmd_start(struct rockchip_rga *rga, + struct rga_runqueue_node *runqueue) +{ + int ret; + + ret = pm_runtime_get_sync(rga->dev); + if (ret < 0) + return; + + rga_write(rga, RGA_SYS_CTRL, 0x00); + + rga_write(rga, RGA_CMD_BASE, runqueue->cmdlist_pool); + + rga_write(rga, RGA_SYS_CTRL, 0x22); + + rga_write(rga, RGA_INT, 0x600); + + rga_write(rga, RGA_CMD_CTRL, ((runqueue->cmdlist_cnt - 1) << 3) | 0x1); +} + +static void rga_free_runqueue_node(struct rockchip_rga *rga, + struct rga_runqueue_node *runqueue) +{ + struct rga_cmdlist_node *node; + + if (!runqueue) + return; + + if (runqueue->cmdlist_pool_virt && runqueue->cmdlist_pool) + dma_free_attrs(rga->dev, runqueue->cmdlist_cnt * RGA_CMDLIST_SIZE, + runqueue->cmdlist_pool_virt, + runqueue->cmdlist_pool, + &runqueue->cmdlist_dma_attrs); + + mutex_lock(&rga->cmdlist_mutex); + /* + * commands in run_cmdlist have been completed so unmap all gem + * objects in each command node so that they are unreferenced. + */ + list_for_each_entry(node, &runqueue->run_cmdlist, list) + rga_unmap_cmdlist_gem(rga, node); + list_splice_tail_init(&runqueue->run_cmdlist, &rga->free_cmdlist); + mutex_unlock(&rga->cmdlist_mutex); + + kmem_cache_free(rga->runqueue_slab, runqueue); +} + +static struct rga_runqueue_node *rga_get_runqueue(struct rockchip_rga *rga) +{ + struct rga_runqueue_node *runqueue; + + if (list_empty(&rga->runqueue_list)) + return NULL; + + runqueue = list_first_entry(&rga->runqueue_list, + struct rga_runqueue_node, list); + list_del_init(&runqueue->list); + + return runqueue; +} + +static void rga_exec_runqueue(struct rockchip_rga *rga) +{ + rga->runqueue_node = rga_get_runqueue(rga); + if (rga->runqueue_node) + rga_cmd_start(rga, rga->runqueue_node); +} + +static struct rga_cmdlist_node *rga_get_cmdlist(struct rockchip_rga *rga) +{ + struct rga_cmdlist_node *node; + struct device *dev = rga->dev; + + mutex_lock(&rga->cmdlist_mutex); + if (list_empty(&rga->free_cmdlist)) { + dev_err(dev, "there is no free cmdlist\n"); + mutex_unlock(&rga->cmdlist_mutex); + return NULL; + } + + node = list_first_entry(&rga->free_cmdlist, + struct rga_cmdlist_node, list); + list_del_init(&node->list); + mutex_unlock(&rga->cmdlist_mutex); + + return node; +} + +static void rga_add_cmdlist_to_inuse(struct rockchip_drm_rga_private *rga_priv, + struct rga_cmdlist_node *node) +{ + struct rga_cmdlist_node *lnode; + + if (list_empty(&rga_priv->inuse_cmdlist)) + goto add_to_list; + + /* this links to base address of new cmdlist */ + lnode = list_entry(rga_priv->inuse_cmdlist.prev, + struct rga_cmdlist_node, list); + +add_to_list: + list_add_tail(&node->list, &rga_priv->inuse_cmdlist); +} + +/* + * IOCRL functions for userspace to get RGA version. + */ +int rockchip_rga_get_ver_ioctl(struct drm_device *drm_dev, void *data, + struct drm_file *file) +{ + struct rockchip_drm_file_private *file_priv = file->driver_priv; + struct rockchip_drm_rga_private *rga_priv = file_priv->rga_priv; + struct drm_rockchip_rga_get_ver *ver = data; + struct rockchip_rga *rga; + struct device *dev; + + if (!rga_priv) + return -ENODEV; + + dev = rga_priv->dev; + if (!dev) + return -ENODEV; + + rga = dev_get_drvdata(dev); + if (!rga) + return -EFAULT; + + ver->major = rga->version.major; + ver->minor = rga->version.minor; + + return 0; +} + +/* + * IOCRL functions for userspace to send an RGA request. + */ +int rockchip_rga_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data, + struct drm_file *file) +{ + struct rockchip_drm_file_private *file_priv = file->driver_priv; + struct rockchip_drm_rga_private *rga_priv = file_priv->rga_priv; + struct drm_rockchip_rga_set_cmdlist *req = data; + struct rga_cmdlist_node *node; + struct rga_cmdlist *cmdlist; + struct rockchip_rga *rga; + int ret; + + if (!rga_priv) + return -ENODEV; + + if (!rga_priv->dev) + return -ENODEV; + + rga = dev_get_drvdata(rga_priv->dev); + if (!rga) + return -EFAULT; + + node = rga_get_cmdlist(rga); + if (!node) + return -ENOMEM; + + cmdlist = &node->cmdlist; + cmdlist->last = 0; + + if (req->cmd_nr > RGA_CMDLIST_SIZE || req->cmd_buf_nr > RGA_CMDBUF_SIZE) { + dev_err(rga->dev, "cmdlist size is too big\n"); + return -EINVAL; + } + + /* + * Copy the command / buffer registers setting from userspace, each + * command have two integer, one for register offset, another for + * register value. + */ + if (copy_from_user((void *)cmdlist->data, (const void __user *)req->cmd, + sizeof(struct drm_rockchip_rga_cmd) * req->cmd_nr)) + return -EFAULT; + cmdlist->last += req->cmd_nr * 2; + + if (copy_from_user((void *)cmdlist->data + cmdlist->last, + (const void __user *)req->cmd_buf, + sizeof(struct drm_rockchip_rga_cmd) * req->cmd_buf_nr)) + return -EFAULT; + cmdlist->last += req->cmd_buf_nr * 2; + + /* + * Check the userspace command registers, and mapping the framebuffer, + * create the RGA mmu pages or get the framebuffer dma address. + */ + ret = rga_check_reg_offset(rga->dev, node); + if (ret < 0) + return ret; + + ret = rga_map_cmdlist_gem(rga, node, drm_dev, file); + if (ret < 0) + return ret; + + rga_add_cmdlist_to_inuse(rga_priv, node); + + return 0; +} + +/* + * IOCRL functions for userspace to start RGA transform. + */ +int rockchip_rga_exec_ioctl(struct drm_device *drm_dev, void *data, + struct drm_file *file) +{ + struct rockchip_drm_file_private *file_priv = file->driver_priv; + struct rockchip_drm_rga_private *rga_priv = file_priv->rga_priv; + struct rga_runqueue_node *runqueue; + struct rockchip_rga *rga; + struct device *dev; + int ret; + + if (!rga_priv) + return -ENODEV; + + dev = rga_priv->dev; + if (!dev) + return -ENODEV; + + rga = dev_get_drvdata(dev); + if (!rga) + return -EFAULT; + + runqueue = kmem_cache_alloc(rga->runqueue_slab, GFP_KERNEL); + if (!runqueue) { + dev_err(rga->dev, "failed to allocate memory\n"); + return -ENOMEM; + } + + runqueue->dev = rga->dev; + + init_completion(&runqueue->complete); + + INIT_LIST_HEAD(&runqueue->run_cmdlist); + + list_splice_init(&rga_priv->inuse_cmdlist, &runqueue->run_cmdlist); + + if (list_empty(&runqueue->run_cmdlist)) { + dev_err(rga->dev, "there is no inuse cmdlist\n"); + kmem_cache_free(rga->runqueue_slab, runqueue); + return -EPERM; + } + + ret = rga_alloc_dma_buf_for_cmdlist(runqueue); + if (ret < 0) { + dev_err(rga->dev, "cmdlist init failed\n"); + return ret; + } + + mutex_lock(&rga->runqueue_mutex); + runqueue->pid = current->pid; + runqueue->file = file; + list_add_tail(&runqueue->list, &rga->runqueue_list); + if (!rga->runqueue_node) + rga_exec_runqueue(rga); + mutex_unlock(&rga->runqueue_mutex); + + wait_for_completion(&runqueue->complete); + rga_free_runqueue_node(rga, runqueue); + + return 0; +} + +static int rockchip_rga_open(struct drm_device *drm_dev, struct device *dev, + struct drm_file *file) +{ + struct rockchip_drm_file_private *file_priv = file->driver_priv; + struct rockchip_drm_rga_private *rga_priv; + + rga_priv = kzalloc(sizeof(*rga_priv), GFP_KERNEL); + if (!rga_priv) + return -ENOMEM; + + rga_priv->dev = dev; + file_priv->rga_priv = rga_priv; + + INIT_LIST_HEAD(&rga_priv->inuse_cmdlist); + + return 0; +} + +static void rockchip_rga_close(struct drm_device *drm_dev, struct device *dev, + struct drm_file *file) +{ + struct rockchip_drm_file_private *file_priv = file->driver_priv; + struct rockchip_drm_rga_private *rga_priv = file_priv->rga_priv; + struct rga_cmdlist_node *node, *n; + struct rockchip_rga *rga; + + if (!dev) + return; + + rga = dev_get_drvdata(dev); + if (!rga) + return; + + mutex_lock(&rga->cmdlist_mutex); + list_for_each_entry_safe(node, n, &rga_priv->inuse_cmdlist, list) { + /* + * unmap all gem objects not completed. + * + * P.S. if current process was terminated forcely then + * there may be some commands in inuse_cmdlist so unmap + * them. + */ + rga_unmap_cmdlist_gem(rga, node); + list_move_tail(&node->list, &rga->free_cmdlist); + } + mutex_unlock(&rga->cmdlist_mutex); + + kfree(file_priv->rga_priv); +} + +static void rga_runqueue_worker(struct work_struct *work) +{ + struct rockchip_rga *rga = container_of(work, struct rockchip_rga, + runqueue_work); + + mutex_lock(&rga->runqueue_mutex); + pm_runtime_put_sync(rga->dev); + + complete(&rga->runqueue_node->complete); + + if (rga->suspended) + rga->runqueue_node = NULL; + else + rga_exec_runqueue(rga); + + mutex_unlock(&rga->runqueue_mutex); +} + +static irqreturn_t rga_irq_handler(int irq, void *dev_id) +{ + struct rockchip_rga *rga = dev_id; + int intr; + + intr = rga_read(rga, RGA_INT) & 0xf; + + rga_mod(rga, RGA_INT, intr << 4, 0xf << 4); + + if (intr & 0x04) + queue_work(rga->rga_workq, &rga->runqueue_work); + + return IRQ_HANDLED; +} + +static int rga_parse_dt(struct rockchip_rga *rga) +{ + struct reset_control *sclk_rst, *aclk_rst, *hclk_rst; + + sclk_rst = devm_reset_control_get(rga->dev, "sclk"); + if (IS_ERR(sclk_rst)) { + dev_err(rga->dev, "failed to get sclk reset controller\n"); + return PTR_ERR(sclk_rst); + } + + aclk_rst = devm_reset_control_get(rga->dev, "aclk"); + if (IS_ERR(aclk_rst)) { + dev_err(rga->dev, "failed to get aclk reset controller\n"); + return PTR_ERR(aclk_rst); + } + + hclk_rst = devm_reset_control_get(rga->dev, "hclk"); + if (IS_ERR(hclk_rst)) { + dev_err(rga->dev, "failed to get hclk reset controller\n"); + return PTR_ERR(hclk_rst); + } + + reset_control_assert(sclk_rst); + usleep_range(10, 20); + reset_control_deassert(sclk_rst); + + reset_control_assert(aclk_rst); + usleep_range(10, 20); + reset_control_deassert(aclk_rst); + + reset_control_assert(hclk_rst); + usleep_range(10, 20); + reset_control_deassert(hclk_rst); + + rga->sclk = devm_clk_get(rga->dev, "sclk"); + if (IS_ERR(rga->sclk)) { + dev_err(rga->dev, "failed to get sclk clock\n"); + return PTR_ERR(rga->sclk); + } + + rga->aclk = devm_clk_get(rga->dev, "aclk"); + if (IS_ERR(rga->aclk)) { + dev_err(rga->dev, "failed to get aclk clock\n"); + return PTR_ERR(rga->aclk); + } + + rga->hclk = devm_clk_get(rga->dev, "hclk"); + if (IS_ERR(rga->hclk)) { + dev_err(rga->dev, "failed to get hclk clock\n"); + return PTR_ERR(rga->hclk); + } + + return rga_enable_clocks(rga); +} + +static const struct of_device_id rockchip_rga_dt_ids[] = { + { .compatible = "rockchip,rk3288-rga", }, + { .compatible = "rockchip,rk3228-rga", }, + { .compatible = "rockchip,rk3399-rga", }, + {}, +}; +MODULE_DEVICE_TABLE(of, rockchip_rga_dt_ids); + +static int rga_probe(struct platform_device *pdev) +{ + struct drm_rockchip_subdrv *subdrv; + struct rockchip_rga *rga; + struct resource *iores; + int irq; + int ret; + + if (!pdev->dev.of_node) + return -ENODEV; + + rga = devm_kzalloc(&pdev->dev, sizeof(*rga), GFP_KERNEL); + if (!rga) + return -ENOMEM; + + rga->dev = &pdev->dev; + + rga->runqueue_slab = kmem_cache_create("rga_runqueue_slab", + sizeof(struct rga_runqueue_node), + 0, 0, NULL); + if (!rga->runqueue_slab) + return -ENOMEM; + + rga->rga_workq = create_singlethread_workqueue("rga"); + if (!rga->rga_workq) { + dev_err(rga->dev, "failed to create workqueue\n"); + goto err_destroy_slab; + } + + INIT_WORK(&rga->runqueue_work, rga_runqueue_worker); + INIT_LIST_HEAD(&rga->runqueue_list); + mutex_init(&rga->runqueue_mutex); + + INIT_LIST_HEAD(&rga->free_cmdlist); + mutex_init(&rga->cmdlist_mutex); + + rga_init_cmdlist(rga); + + ret = rga_parse_dt(rga); + if (ret) { + dev_err(rga->dev, "Unable to parse OF data\n"); + goto err_destroy_workqueue; + } + + pm_runtime_enable(rga->dev); + + iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + rga->regs = devm_ioremap_resource(rga->dev, iores); + if (IS_ERR(rga->regs)) { + ret = PTR_ERR(rga->regs); + goto err_put_clk; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(rga->dev, "failed to get irq\n"); + ret = irq; + goto err_put_clk; + } + + ret = devm_request_irq(rga->dev, irq, rga_irq_handler, 0, + dev_name(rga->dev), rga); + if (ret < 0) { + dev_err(rga->dev, "failed to request irq\n"); + goto err_put_clk; + } + + platform_set_drvdata(pdev, rga); + + rga->version.major = (rga_read(rga, RGA_VERSION_INFO) >> 24) & 0xFF; + rga->version.minor = (rga_read(rga, RGA_VERSION_INFO) >> 20) & 0x0F; + + subdrv = &rga->subdrv; + subdrv->dev = rga->dev; + subdrv->open = rockchip_rga_open; + subdrv->close = rockchip_rga_close; + + rockchip_register_subdrv(subdrv); + + return 0; + +err_put_clk: + pm_runtime_disable(rga->dev); +err_destroy_workqueue: + destroy_workqueue(rga->rga_workq); +err_destroy_slab: + kmem_cache_destroy(rga->runqueue_slab); + + return ret; +} + +static int rga_remove(struct platform_device *pdev) +{ + struct rockchip_rga *rga = platform_get_drvdata(pdev); + + cancel_work_sync(&rga->runqueue_work); + + while (rga->runqueue_node) { + rga_free_runqueue_node(rga, rga->runqueue_node); + rga->runqueue_node = rga_get_runqueue(rga); + } + + rockchip_unregister_subdrv(&rga->subdrv); + + return 0; +} + +static int rga_suspend(struct device *dev) +{ + struct rockchip_rga *rga = dev_get_drvdata(dev); + + mutex_lock(&rga->runqueue_mutex); + rga->suspended = true; + mutex_unlock(&rga->runqueue_mutex); + + flush_work(&rga->runqueue_work); + + return 0; +} + +static int rga_resume(struct device *dev) +{ + struct rockchip_rga *rga = dev_get_drvdata(dev); + + rga->suspended = false; + rga_exec_runqueue(rga); + + return 0; +} + +#ifdef CONFIG_PM +static int rga_runtime_suspend(struct device *dev) +{ + struct rockchip_rga *rga = dev_get_drvdata(dev); + + rga_disable_clocks(rga); + + return 0; +} + +static int rga_runtime_resume(struct device *dev) +{ + struct rockchip_rga *rga = dev_get_drvdata(dev); + + return rga_enable_clocks(rga); +} +#endif + +static const struct dev_pm_ops rga_pm = { + SET_SYSTEM_SLEEP_PM_OPS(rga_suspend, rga_resume) + SET_RUNTIME_PM_OPS(rga_runtime_suspend, + rga_runtime_resume, NULL) +}; + +static struct platform_driver rga_pltfm_driver = { + .probe = rga_probe, + .remove = rga_remove, + .driver = { + .name = "rockchip-rga", + .pm = &rga_pm, + .of_match_table = rockchip_rga_dt_ids, + }, +}; + +module_platform_driver(rga_pltfm_driver); + +MODULE_AUTHOR("Yakir Yang "); +MODULE_DESCRIPTION("Rockchip RGA Driver Extension"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:rockchip-rga"); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_rga.h b/drivers/gpu/drm/rockchip/rockchip_drm_rga.h new file mode 100644 index 0000000..4a8839a --- /dev/null +++ b/drivers/gpu/drm/rockchip/rockchip_drm_rga.h @@ -0,0 +1,108 @@ +#ifndef __ROCKCHIP_DRM_RGA__ +#define __ROCKCHIP_DRM_RGA__ + +#define RGA_CMDBUF_SIZE 14 +#define RGA_CMDLIST_SIZE 0x20 +#define RGA_CMDLIST_NUM 64 + +/* cmdlist data structure */ +struct rga_cmdlist { + u32 head; + unsigned long data[RGA_CMDLIST_SIZE * 2]; + u32 last; /* last data offset */ + void *src_mmu_pages; + void *dst_mmu_pages; + void *src1_mmu_pages; + struct dma_buf_attachment *src_attach; + struct dma_buf_attachment *dst_attach; +}; + +struct rga_cmdlist_node { + struct list_head list; + struct rga_cmdlist cmdlist; +}; + +struct rga_runqueue_node { + struct list_head list; + + struct device *dev; + pid_t pid; + struct drm_file *file; + struct completion complete; + + struct list_head run_cmdlist; + + int cmdlist_cnt; + void *cmdlist_pool_virt; + dma_addr_t cmdlist_pool; + struct dma_attrs cmdlist_dma_attrs; +}; + +struct rockchip_rga_version { + __u32 major; + __u32 minor; +}; + +struct rockchip_rga { + struct drm_device *drm_dev; + struct device *dev; + struct regmap *grf; + void __iomem *regs; + struct clk *sclk; + struct clk *aclk; + struct clk *hclk; + + bool suspended; + struct rockchip_rga_version version; + struct drm_rockchip_subdrv subdrv; + struct workqueue_struct *rga_workq; + struct work_struct runqueue_work; + + /* rga command list pool */ + struct rga_cmdlist_node cmdlist_node[RGA_CMDLIST_NUM]; + struct mutex cmdlist_mutex; + + struct list_head free_cmdlist; + + /* rga runqueue */ + struct rga_runqueue_node *runqueue_node; + struct list_head runqueue_list; + struct mutex runqueue_mutex; + struct kmem_cache *runqueue_slab; +}; + +struct rockchip_drm_rga_private { + struct device *dev; + struct list_head inuse_cmdlist; + struct list_head userptr_list; +}; + +#ifdef CONFIG_ROCKCHIP_DRM_RGA +int rockchip_rga_get_ver_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int rockchip_rga_set_cmdlist_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int rockchip_rga_exec_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +#else +static inline int rockchip_rga_get_ver_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + return -ENODEV; +} + +static inline int rockchip_rga_set_cmdlist_ioctl(struct drm_device *dev, + void *data, + struct drm_file *file_priv) +{ + return -ENODEV; +} + +static inline int rockchip_rga_exec_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + return -ENODEV; +} +#endif + +#endif /* __ROCKCHIP_DRM_RGA__ */ diff --git a/include/uapi/drm/rockchip_drm.h b/include/uapi/drm/rockchip_drm.h new file mode 100644 index 0000000..2e3e240 --- /dev/null +++ b/include/uapi/drm/rockchip_drm.h @@ -0,0 +1,63 @@ +/* rockchip_drm.h + * + * Copyright (c) 2016 Fuzhou Rockchip Electronics Co., Ltd. + * Authors: + * Yakir Yang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef _UAPI_ROCKCHIP_DRM_H_ +#define _UAPI_ROCKCHIP_DRM_H_ + +#include + +struct drm_rockchip_rga_get_ver { + __u32 major; + __u32 minor; +}; + +struct drm_rockchip_rga_cmd { + __u32 offset; + __u32 data; +}; + +enum drm_rockchip_rga_buf_type { + RGA_BUF_TYPE_USERPTR = 1 << 31, + RGA_BUF_TYPE_GEMFD = 1 << 30, +}; + +struct drm_rockchip_rga_userptr { + unsigned long userptr; + unsigned long size; +}; + +struct drm_rockchip_rga_set_cmdlist { + __u64 cmd; + __u64 cmd_buf; + __u32 cmd_nr; + __u32 cmd_buf_nr; + __u64 user_data; +}; + +struct drm_rockchip_rga_exec { + __u64 async; +}; + +#define DRM_ROCKCHIP_RGA_GET_VER 0x20 +#define DRM_ROCKCHIP_RGA_SET_CMDLIST 0x21 +#define DRM_ROCKCHIP_RGA_EXEC 0x22 + +#define DRM_IOCTL_ROCKCHIP_RGA_GET_VER DRM_IOWR(DRM_COMMAND_BASE + \ + DRM_ROCKCHIP_RGA_GET_VER, struct drm_rockchip_rga_get_ver) + +#define DRM_IOCTL_ROCKCHIP_RGA_SET_CMDLIST DRM_IOWR(DRM_COMMAND_BASE + \ + DRM_ROCKCHIP_RGA_SET_CMDLIST, struct drm_rockchip_rga_set_cmdlist) + +#define DRM_IOCTL_ROCKCHIP_RGA_EXEC DRM_IOWR(DRM_COMMAND_BASE + \ + DRM_ROCKCHIP_RGA_EXEC, struct drm_rockchip_rga_exec) + +#endif /* _UAPI_ROCKCHIP_DRM_H */ -- 1.9.1