From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752155AbdAaUA1 (ORCPT ); Tue, 31 Jan 2017 15:00:27 -0500 Received: from mail-wm0-f66.google.com ([74.125.82.66]:36385 "EHLO mail-wm0-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751865AbdAaUAS (ORCPT ); Tue, 31 Jan 2017 15:00:18 -0500 Date: Tue, 31 Jan 2017 20:51:59 +0100 From: Daniel Vetter To: Eric Anholt Cc: Florian Fainelli , Michael Turquette , Stephen Boyd , Rob Herring , Mark Rutland , dri-devel@lists.freedesktop.org, Thierry Reding , Stephen Warren , Lee Jones , linux-kernel@vger.kernel.org, bcm-kernel-feedback-list@broadcom.com, linux-rpi-kernel@lists.infradead.org, linux-clk@vger.kernel.org, linux-arm-kernel@lists.infradead.org Subject: Re: [PATCH 07/11] drm/vc4: Add DSI driver Message-ID: <20170131195159.kfqfmvtngxzvt63a@phenom.ffwll.local> Mail-Followup-To: Eric Anholt , Florian Fainelli , Michael Turquette , Stephen Boyd , Rob Herring , Mark Rutland , dri-devel@lists.freedesktop.org, Thierry Reding , Stephen Warren , Lee Jones , linux-kernel@vger.kernel.org, bcm-kernel-feedback-list@broadcom.com, linux-rpi-kernel@lists.infradead.org, linux-clk@vger.kernel.org, linux-arm-kernel@lists.infradead.org References: <20161214194621.16499-1-eric@anholt.net> <20161214194621.16499-8-eric@anholt.net> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20161214194621.16499-8-eric@anholt.net> X-Operating-System: Linux phenom 4.8.0-1-amd64 User-Agent: NeoMutt/20161126 (1.7.1) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Wed, Dec 14, 2016 at 11:46:17AM -0800, Eric Anholt wrote: > The DSI0 and DSI1 blocks on the 2835 are related hardware blocks. > Some registers move around, and the featureset is slightly different, > as DSI1 (the 4-lane DSI) is a later version of the hardware block. > This driver doesn't yet enable DSI0, since we don't have any hardware > to test against, but it does put a lot of the register definitions and > code in place. > > Signed-off-by: Eric Anholt Looks all neat, below a few semi-random ideas. Acked-by: Daniel Vetter > --- > drivers/gpu/drm/vc4/Kconfig | 2 + > drivers/gpu/drm/vc4/Makefile | 1 + > drivers/gpu/drm/vc4/vc4_debugfs.c | 1 + > drivers/gpu/drm/vc4/vc4_drv.c | 1 + > drivers/gpu/drm/vc4/vc4_drv.h | 5 + > drivers/gpu/drm/vc4/vc4_dsi.c | 1725 +++++++++++++++++++++++++++++++++++++ > 6 files changed, 1735 insertions(+) > create mode 100644 drivers/gpu/drm/vc4/vc4_dsi.c > > diff --git a/drivers/gpu/drm/vc4/Kconfig b/drivers/gpu/drm/vc4/Kconfig > index e53df59cb139..e1517d07cb7d 100644 > --- a/drivers/gpu/drm/vc4/Kconfig > +++ b/drivers/gpu/drm/vc4/Kconfig > @@ -2,10 +2,12 @@ config DRM_VC4 > tristate "Broadcom VC4 Graphics" > depends on ARCH_BCM2835 || COMPILE_TEST > depends on DRM > + depends on COMMON_CLK > select DRM_KMS_HELPER > select DRM_KMS_CMA_HELPER > select DRM_GEM_CMA_HELPER > select DRM_PANEL > + select DRM_MIPI_DSI > help > Choose this option if you have a system that has a Broadcom > VC4 GPU, such as the Raspberry Pi or other BCM2708/BCM2835. > diff --git a/drivers/gpu/drm/vc4/Makefile b/drivers/gpu/drm/vc4/Makefile > index 7757f69a8a77..61f45d122bd0 100644 > --- a/drivers/gpu/drm/vc4/Makefile > +++ b/drivers/gpu/drm/vc4/Makefile > @@ -8,6 +8,7 @@ vc4-y := \ > vc4_crtc.o \ > vc4_drv.o \ > vc4_dpi.o \ > + vc4_dsi.o \ > vc4_kms.o \ > vc4_gem.o \ > vc4_hdmi.o \ > diff --git a/drivers/gpu/drm/vc4/vc4_debugfs.c b/drivers/gpu/drm/vc4/vc4_debugfs.c > index caf817bac885..3ca476c6e057 100644 > --- a/drivers/gpu/drm/vc4/vc4_debugfs.c > +++ b/drivers/gpu/drm/vc4/vc4_debugfs.c > @@ -18,6 +18,7 @@ > static const struct drm_info_list vc4_debugfs_list[] = { > {"bo_stats", vc4_bo_stats_debugfs, 0}, > {"dpi_regs", vc4_dpi_debugfs_regs, 0}, > + {"dsi1_regs", vc4_dsi_debugfs_regs, 0, (void *)(uintptr_t)1}, > {"hdmi_regs", vc4_hdmi_debugfs_regs, 0}, > {"vec_regs", vc4_vec_debugfs_regs, 0}, > {"hvs_regs", vc4_hvs_debugfs_regs, 0}, > diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c > index bdab333979dc..2d2edc7dcf4a 100644 > --- a/drivers/gpu/drm/vc4/vc4_drv.c > +++ b/drivers/gpu/drm/vc4/vc4_drv.c > @@ -298,6 +298,7 @@ static struct platform_driver *const component_drivers[] = { > &vc4_hdmi_driver, > &vc4_vec_driver, > &vc4_dpi_driver, > + &vc4_dsi_driver, > &vc4_hvs_driver, > &vc4_crtc_driver, > &vc4_v3d_driver, > diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h > index b5c4bb14d0d1..723f0ec940ac 100644 > --- a/drivers/gpu/drm/vc4/vc4_drv.h > +++ b/drivers/gpu/drm/vc4/vc4_drv.h > @@ -17,6 +17,7 @@ struct vc4_dev { > struct vc4_crtc *crtc[3]; > struct vc4_v3d *v3d; > struct vc4_dpi *dpi; > + struct vc4_dsi *dsi1; > struct vc4_vec *vec; > > struct drm_fbdev_cma *fbdev; > @@ -465,6 +466,10 @@ void __iomem *vc4_ioremap_regs(struct platform_device *dev, int index); > extern struct platform_driver vc4_dpi_driver; > int vc4_dpi_debugfs_regs(struct seq_file *m, void *unused); > > +/* vc4_dsi.c */ > +extern struct platform_driver vc4_dsi_driver; > +int vc4_dsi_debugfs_regs(struct seq_file *m, void *unused); > + > /* vc4_gem.c */ > void vc4_gem_init(struct drm_device *dev); > void vc4_gem_destroy(struct drm_device *dev); > diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c > new file mode 100644 > index 000000000000..17fcac381dbb > --- /dev/null > +++ b/drivers/gpu/drm/vc4/vc4_dsi.c > @@ -0,0 +1,1725 @@ > +/* > + * Copyright (C) 2016 Broadcom > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License version 2 as published by > + * the Free Software Foundation. > + * > + * 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. > + * > + * You should have received a copy of the GNU General Public License along with > + * this program. If not, see . > + */ > + > +/** > + * DOC: VC4 DSI0/DSI1 module Since you're bothering with kerneldoc, I strongly recommend you add a vc4.rst in Documentation/gpu, include it together with the other drivers (atm only i915, but Noralf will add one for tinydrm) and then add stanzas to pull your kerneldoc in. That's the only way to lint it (at least for now, until maybe we merge Jani's make target to lint all the kerneldocs), and I think slowly building up driver docs would be really sweet. Anyway, just an idea for the future. > + * > + * BCM2835 contains two DSI modules, DSI0 and DSI1. DSI0 is a > + * single-lane DSI controller, while DSI1 is a more modern 4-lane DSI > + * controller. > + * > + * Most Raspberry Pi boards expose DSI1 as their "DISPLAY" connector, > + * while the compute module brings both DSI0 and DSI1 out. > + * > + * This driver has been tested for DSI1 video-mode display only > + * currently, with most of the information necessary for DSI0 > + * hopefully present. > + */ > + > +#include "drm_atomic_helper.h" > +#include "drm_crtc_helper.h" > +#include "drm_edid.h" > +#include "drm_mipi_dsi.h" > +#include "drm_panel.h" > +#include "linux/clk.h" > +#include "linux/clk-provider.h" > +#include "linux/completion.h" > +#include "linux/component.h" > +#include "linux/dmaengine.h" > +#include "linux/i2c.h" > +#include "linux/of_address.h" > +#include "linux/of_platform.h" > +#include "linux/pm_runtime.h" > +#include "vc4_drv.h" > +#include "vc4_regs.h" > + > +#define DSI_CMD_FIFO_DEPTH 16 > +#define DSI_PIX_FIFO_DEPTH 256 > +#define DSI_PIX_FIFO_WIDTH 4 > + > +#define DSI0_CTRL 0x00 > + > +/* Command packet control. */ > +#define DSI0_TXPKT1C 0x04 /* AKA PKTC */ > +#define DSI1_TXPKT1C 0x04 > +# define DSI_TXPKT1C_TRIG_CMD_MASK VC4_MASK(31, 24) > +# define DSI_TXPKT1C_TRIG_CMD_SHIFT 24 > +# define DSI_TXPKT1C_CMD_REPEAT_MASK VC4_MASK(23, 10) > +# define DSI_TXPKT1C_CMD_REPEAT_SHIFT 10 > + > +# define DSI_TXPKT1C_DISPLAY_NO_MASK VC4_MASK(9, 8) > +# define DSI_TXPKT1C_DISPLAY_NO_SHIFT 8 > +/* Short, trigger, BTA, or a long packet that fits all in CMDFIFO. */ > +# define DSI_TXPKT1C_DISPLAY_NO_SHORT 0 > +/* Primary display where cmdfifo provides part of the payload and > + * pixelvalve the rest. > + */ > +# define DSI_TXPKT1C_DISPLAY_NO_PRIMARY 1 > +/* Secondary display where cmdfifo provides part of the payload and > + * pixfifo the rest. > + */ > +# define DSI_TXPKT1C_DISPLAY_NO_SECONDARY 2 > + > +# define DSI_TXPKT1C_CMD_TX_TIME_MASK VC4_MASK(7, 6) > +# define DSI_TXPKT1C_CMD_TX_TIME_SHIFT 6 > + > +# define DSI_TXPKT1C_CMD_CTRL_MASK VC4_MASK(5, 4) > +# define DSI_TXPKT1C_CMD_CTRL_SHIFT 4 > +/* Command only. Uses TXPKT1H and DISPLAY_NO */ > +# define DSI_TXPKT1C_CMD_CTRL_TX 0 > +/* Command with BTA for either ack or read data. */ > +# define DSI_TXPKT1C_CMD_CTRL_RX 1 > +/* Trigger according to TRIG_CMD */ > +# define DSI_TXPKT1C_CMD_CTRL_TRIG 2 > +/* BTA alone for getting error status after a command, or a TE trigger > + * without a previous command. > + */ > +# define DSI_TXPKT1C_CMD_CTRL_BTA 3 > + > +# define DSI_TXPKT1C_CMD_MODE_LP BIT(3) > +# define DSI_TXPKT1C_CMD_TYPE_LONG BIT(2) > +# define DSI_TXPKT1C_CMD_TE_EN BIT(1) > +# define DSI_TXPKT1C_CMD_EN BIT(0) > + > +/* Command packet header. */ > +#define DSI0_TXPKT1H 0x08 /* AKA PKTH */ > +#define DSI1_TXPKT1H 0x08 > +# define DSI_TXPKT1H_BC_CMDFIFO_MASK VC4_MASK(31, 24) > +# define DSI_TXPKT1H_BC_CMDFIFO_SHIFT 24 > +# define DSI_TXPKT1H_BC_PARAM_MASK VC4_MASK(23, 8) > +# define DSI_TXPKT1H_BC_PARAM_SHIFT 8 > +# define DSI_TXPKT1H_BC_DT_MASK VC4_MASK(7, 0) > +# define DSI_TXPKT1H_BC_DT_SHIFT 0 > + > +#define DSI0_RXPKT1H 0x0c /* AKA RX1_PKTH */ > +#define DSI1_RXPKT1H 0x14 > +# define DSI_RXPKT1H_CRC_ERR BIT(31) > +# define DSI_RXPKT1H_DET_ERR BIT(30) > +# define DSI_RXPKT1H_ECC_ERR BIT(29) > +# define DSI_RXPKT1H_COR_ERR BIT(28) > +# define DSI_RXPKT1H_INCOMP_PKT BIT(25) > +# define DSI_RXPKT1H_PKT_TYPE_LONG BIT(24) > +/* Byte count if DSI_RXPKT1H_PKT_TYPE_LONG */ > +# define DSI_RXPKT1H_BC_PARAM_MASK VC4_MASK(23, 8) > +# define DSI_RXPKT1H_BC_PARAM_SHIFT 8 > +/* Short return bytes if !DSI_RXPKT1H_PKT_TYPE_LONG */ > +# define DSI_RXPKT1H_SHORT_1_MASK VC4_MASK(23, 16) > +# define DSI_RXPKT1H_SHORT_1_SHIFT 16 > +# define DSI_RXPKT1H_SHORT_0_MASK VC4_MASK(15, 8) > +# define DSI_RXPKT1H_SHORT_0_SHIFT 8 > +# define DSI_RXPKT1H_DT_LP_CMD_MASK VC4_MASK(7, 0) > +# define DSI_RXPKT1H_DT_LP_CMD_SHIFT 0 > + > +#define DSI0_RXPKT2H 0x10 /* AKA RX2_PKTH */ > +#define DSI1_RXPKT2H 0x18 > +# define DSI_RXPKT1H_DET_ERR BIT(30) > +# define DSI_RXPKT1H_ECC_ERR BIT(29) > +# define DSI_RXPKT1H_COR_ERR BIT(28) > +# define DSI_RXPKT1H_INCOMP_PKT BIT(25) > +# define DSI_RXPKT1H_BC_PARAM_MASK VC4_MASK(23, 8) > +# define DSI_RXPKT1H_BC_PARAM_SHIFT 8 > +# define DSI_RXPKT1H_DT_MASK VC4_MASK(7, 0) > +# define DSI_RXPKT1H_DT_SHIFT 0 > + > +#define DSI0_TXPKT_CMD_FIFO 0x14 /* AKA CMD_DATAF */ > +#define DSI1_TXPKT_CMD_FIFO 0x1c > + > +#define DSI0_DISP0_CTRL 0x18 > +# define DSI_DISP0_PIX_CLK_DIV_MASK VC4_MASK(21, 13) > +# define DSI_DISP0_PIX_CLK_DIV_SHIFT 13 > +# define DSI_DISP0_LP_STOP_CTRL_MASK VC4_MASK(12, 11) > +# define DSI_DISP0_LP_STOP_CTRL_SHIFT 11 > +# define DSI_DISP0_LP_STOP_DISABLE 0 > +# define DSI_DISP0_LP_STOP_PERLINE 1 > +# define DSI_DISP0_LP_STOP_PERFRAME 2 > + > +/* Transmit RGB pixels and null packets only during HACTIVE, instead > + * of going to LP-STOP. > + */ > +# define DSI_DISP_HACTIVE_NULL BIT(10) > +/* Transmit blanking packet only during vblank, instead of allowing LP-STOP. */ > +# define DSI_DISP_VBLP_CTRL BIT(9) > +/* Transmit blanking packet only during HFP, instead of allowing LP-STOP. */ > +# define DSI_DISP_HFP_CTRL BIT(8) > +/* Transmit blanking packet only during HBP, instead of allowing LP-STOP. */ > +# define DSI_DISP_HBP_CTRL BIT(7) > +# define DSI_DISP0_CHANNEL_MASK VC4_MASK(6, 5) > +# define DSI_DISP0_CHANNEL_SHIFT 5 > +/* Enables end events for HSYNC/VSYNC, not just start events. */ > +# define DSI_DISP0_ST_END BIT(4) > +# define DSI_DISP0_PFORMAT_MASK VC4_MASK(3, 2) > +# define DSI_DISP0_PFORMAT_SHIFT 2 > +# define DSI_PFORMAT_RGB565 0 > +# define DSI_PFORMAT_RGB666_PACKED 1 > +# define DSI_PFORMAT_RGB666 2 > +# define DSI_PFORMAT_RGB888 3 > +/* Default is VIDEO mode. */ > +# define DSI_DISP0_COMMAND_MODE BIT(1) > +# define DSI_DISP0_ENABLE BIT(0) > + > +#define DSI0_DISP1_CTRL 0x1c > +#define DSI1_DISP1_CTRL 0x2c > +/* Format of the data written to TXPKT_PIX_FIFO. */ > +# define DSI_DISP1_PFORMAT_MASK VC4_MASK(2, 1) > +# define DSI_DISP1_PFORMAT_SHIFT 1 > +# define DSI_DISP1_PFORMAT_16BIT 0 > +# define DSI_DISP1_PFORMAT_24BIT 1 > +# define DSI_DISP1_PFORMAT_32BIT_LE 2 > +# define DSI_DISP1_PFORMAT_32BIT_BE 3 > + > +/* DISP1 is always command mode. */ > +# define DSI_DISP1_ENABLE BIT(0) > + > +#define DSI0_TXPKT_PIX_FIFO 0x20 /* AKA PIX_FIFO */ > + > +#define DSI0_INT_STAT 0x24 > +#define DSI0_INT_EN 0x28 > +# define DSI1_INT_PHY_D3_ULPS BIT(30) > +# define DSI1_INT_PHY_D3_STOP BIT(29) > +# define DSI1_INT_PHY_D2_ULPS BIT(28) > +# define DSI1_INT_PHY_D2_STOP BIT(27) > +# define DSI1_INT_PHY_D1_ULPS BIT(26) > +# define DSI1_INT_PHY_D1_STOP BIT(25) > +# define DSI1_INT_PHY_D0_ULPS BIT(24) > +# define DSI1_INT_PHY_D0_STOP BIT(23) > +# define DSI1_INT_FIFO_ERR BIT(22) > +# define DSI1_INT_PHY_DIR_RTF BIT(21) > +# define DSI1_INT_PHY_RXLPDT BIT(20) > +# define DSI1_INT_PHY_RXTRIG BIT(19) > +# define DSI1_INT_PHY_D0_LPDT BIT(18) > +# define DSI1_INT_PHY_DIR_FTR BIT(17) > + > +/* Signaled when the clock lane enters the given state. */ > +# define DSI1_INT_PHY_CLOCK_ULPS BIT(16) > +# define DSI1_INT_PHY_CLOCK_HS BIT(15) > +# define DSI1_INT_PHY_CLOCK_STOP BIT(14) > + > +/* Signaled on timeouts */ > +# define DSI1_INT_PR_TO BIT(13) > +# define DSI1_INT_TA_TO BIT(12) > +# define DSI1_INT_LPRX_TO BIT(11) > +# define DSI1_INT_HSTX_TO BIT(10) > + > +/* Contention on a line when trying to drive the line low */ > +# define DSI1_INT_ERR_CONT_LP1 BIT(9) > +# define DSI1_INT_ERR_CONT_LP0 BIT(8) > + > +/* Control error: incorrect line state sequence on data lane 0. */ > +# define DSI1_INT_ERR_CONTROL BIT(7) > +/* LPDT synchronization error (bits received not a multiple of 8. */ > + > +# define DSI1_INT_ERR_SYNC_ESC BIT(6) > +/* Signaled after receiving an error packet from the display in > + * response to a read. > + */ > +# define DSI1_INT_RXPKT2 BIT(5) > +/* Signaled after receiving a packet. The header and optional short > + * response will be in RXPKT1H, and a long response will be in the > + * RXPKT_FIFO. > + */ > +# define DSI1_INT_RXPKT1 BIT(4) > +# define DSI1_INT_TXPKT2_DONE BIT(3) > +# define DSI1_INT_TXPKT2_END BIT(2) > +/* Signaled after all repeats of TXPKT1 are transferred. */ > +# define DSI1_INT_TXPKT1_DONE BIT(1) > +/* Signaled after each TXPKT1 repeat is scheduled. */ > +# define DSI1_INT_TXPKT1_END BIT(0) > + > +#define DSI1_INTERRUPTS_ALWAYS_ENABLED (DSI1_INT_ERR_SYNC_ESC | \ > + DSI1_INT_ERR_CONTROL | \ > + DSI1_INT_ERR_CONT_LP0 | \ > + DSI1_INT_ERR_CONT_LP1 | \ > + DSI1_INT_HSTX_TO | \ > + DSI1_INT_LPRX_TO | \ > + DSI1_INT_TA_TO | \ > + DSI1_INT_PR_TO) > + > +#define DSI0_STAT 0x2c > +#define DSI0_HSTX_TO_CNT 0x30 > +#define DSI0_LPRX_TO_CNT 0x34 > +#define DSI0_TA_TO_CNT 0x38 > +#define DSI0_PR_TO_CNT 0x3c > +#define DSI0_PHYC 0x40 > +# define DSI1_PHYC_ESC_CLK_LPDT_MASK VC4_MASK(25, 20) > +# define DSI1_PHYC_ESC_CLK_LPDT_SHIFT 20 > +# define DSI1_PHYC_HS_CLK_CONTINUOUS BIT(18) > +# define DSI0_PHYC_ESC_CLK_LPDT_MASK VC4_MASK(17, 12) > +# define DSI0_PHYC_ESC_CLK_LPDT_SHIFT 12 > +# define DSI1_PHYC_CLANE_ULPS BIT(17) > +# define DSI1_PHYC_CLANE_ENABLE BIT(16) > +# define DSI_PHYC_DLANE3_ULPS BIT(13) > +# define DSI_PHYC_DLANE3_ENABLE BIT(12) > +# define DSI0_PHYC_HS_CLK_CONTINUOUS BIT(10) > +# define DSI0_PHYC_CLANE_ULPS BIT(9) > +# define DSI_PHYC_DLANE2_ULPS BIT(9) > +# define DSI0_PHYC_CLANE_ENABLE BIT(8) > +# define DSI_PHYC_DLANE2_ENABLE BIT(8) > +# define DSI_PHYC_DLANE1_ULPS BIT(5) > +# define DSI_PHYC_DLANE1_ENABLE BIT(4) > +# define DSI_PHYC_DLANE0_FORCE_STOP BIT(2) > +# define DSI_PHYC_DLANE0_ULPS BIT(1) > +# define DSI_PHYC_DLANE0_ENABLE BIT(0) > + > +#define DSI0_HS_CLT0 0x44 > +#define DSI0_HS_CLT1 0x48 > +#define DSI0_HS_CLT2 0x4c > +#define DSI0_HS_DLT3 0x50 > +#define DSI0_HS_DLT4 0x54 > +#define DSI0_HS_DLT5 0x58 > +#define DSI0_HS_DLT6 0x5c > +#define DSI0_HS_DLT7 0x60 > + > +#define DSI0_PHY_AFEC0 0x64 > +# define DSI0_PHY_AFEC0_DDR2CLK_EN BIT(26) > +# define DSI0_PHY_AFEC0_DDRCLK_EN BIT(25) > +# define DSI0_PHY_AFEC0_LATCH_ULPS BIT(24) > +# define DSI1_PHY_AFEC0_IDR_DLANE3_MASK VC4_MASK(31, 29) > +# define DSI1_PHY_AFEC0_IDR_DLANE3_SHIFT 29 > +# define DSI1_PHY_AFEC0_IDR_DLANE2_MASK VC4_MASK(28, 26) > +# define DSI1_PHY_AFEC0_IDR_DLANE2_SHIFT 26 > +# define DSI1_PHY_AFEC0_IDR_DLANE1_MASK VC4_MASK(27, 23) > +# define DSI1_PHY_AFEC0_IDR_DLANE1_SHIFT 23 > +# define DSI1_PHY_AFEC0_IDR_DLANE0_MASK VC4_MASK(22, 20) > +# define DSI1_PHY_AFEC0_IDR_DLANE0_SHIFT 20 > +# define DSI1_PHY_AFEC0_IDR_CLANE_MASK VC4_MASK(19, 17) > +# define DSI1_PHY_AFEC0_IDR_CLANE_SHIFT 17 > +# define DSI0_PHY_AFEC0_ACTRL_DLANE1_MASK VC4_MASK(23, 20) > +# define DSI0_PHY_AFEC0_ACTRL_DLANE1_SHIFT 20 > +# define DSI0_PHY_AFEC0_ACTRL_DLANE0_MASK VC4_MASK(19, 16) > +# define DSI0_PHY_AFEC0_ACTRL_DLANE0_SHIFT 16 > +# define DSI0_PHY_AFEC0_ACTRL_CLANE_MASK VC4_MASK(15, 12) > +# define DSI0_PHY_AFEC0_ACTRL_CLANE_SHIFT 12 > +# define DSI1_PHY_AFEC0_DDR2CLK_EN BIT(16) > +# define DSI1_PHY_AFEC0_DDRCLK_EN BIT(15) > +# define DSI1_PHY_AFEC0_LATCH_ULPS BIT(14) > +# define DSI1_PHY_AFEC0_RESET BIT(13) > +# define DSI1_PHY_AFEC0_PD BIT(12) > +# define DSI0_PHY_AFEC0_RESET BIT(11) > +# define DSI1_PHY_AFEC0_PD_BG BIT(11) > +# define DSI0_PHY_AFEC0_PD BIT(10) > +# define DSI1_PHY_AFEC0_PD_DLANE3 BIT(10) > +# define DSI0_PHY_AFEC0_PD_BG BIT(9) > +# define DSI1_PHY_AFEC0_PD_DLANE2 BIT(9) > +# define DSI0_PHY_AFEC0_PD_DLANE1 BIT(8) > +# define DSI1_PHY_AFEC0_PD_DLANE1 BIT(8) > +# define DSI_PHY_AFEC0_PTATADJ_MASK VC4_MASK(7, 4) > +# define DSI_PHY_AFEC0_PTATADJ_SHIFT 4 > +# define DSI_PHY_AFEC0_CTATADJ_MASK VC4_MASK(3, 0) > +# define DSI_PHY_AFEC0_CTATADJ_SHIFT 0 > + > +#define DSI0_PHY_AFEC1 0x68 > +# define DSI0_PHY_AFEC1_IDR_DLANE1_MASK VC4_MASK(10, 8) > +# define DSI0_PHY_AFEC1_IDR_DLANE1_SHIFT 8 > +# define DSI0_PHY_AFEC1_IDR_DLANE0_MASK VC4_MASK(6, 4) > +# define DSI0_PHY_AFEC1_IDR_DLANE0_SHIFT 4 > +# define DSI0_PHY_AFEC1_IDR_CLANE_MASK VC4_MASK(2, 0) > +# define DSI0_PHY_AFEC1_IDR_CLANE_SHIFT 0 > + > +#define DSI0_TST_SEL 0x6c > +#define DSI0_TST_MON 0x70 > +#define DSI0_ID 0x74 > +# define DSI_ID_VALUE 0x00647369 > + > +#define DSI1_CTRL 0x00 > +# define DSI_CTRL_HS_CLKC_MASK VC4_MASK(15, 14) > +# define DSI_CTRL_HS_CLKC_SHIFT 14 > +# define DSI_CTRL_HS_CLKC_BYTE 0 > +# define DSI_CTRL_HS_CLKC_DDR2 1 > +# define DSI_CTRL_HS_CLKC_DDR 2 > + > +# define DSI_CTRL_RX_LPDT_EOT_DISABLE BIT(13) > +# define DSI_CTRL_LPDT_EOT_DISABLE BIT(12) > +# define DSI_CTRL_HSDT_EOT_DISABLE BIT(11) > +# define DSI_CTRL_SOFT_RESET_CFG BIT(10) > +# define DSI_CTRL_CAL_BYTE BIT(9) > +# define DSI_CTRL_INV_BYTE BIT(8) > +# define DSI_CTRL_CLR_LDF BIT(7) > +# define DSI0_CTRL_CLR_PBCF BIT(6) > +# define DSI1_CTRL_CLR_RXF BIT(6) > +# define DSI0_CTRL_CLR_CPBCF BIT(5) > +# define DSI1_CTRL_CLR_PDF BIT(5) > +# define DSI0_CTRL_CLR_PDF BIT(4) > +# define DSI1_CTRL_CLR_CDF BIT(4) > +# define DSI0_CTRL_CLR_CDF BIT(3) > +# define DSI0_CTRL_CTRL2 BIT(2) > +# define DSI1_CTRL_DISABLE_DISP_CRCC BIT(2) > +# define DSI0_CTRL_CTRL1 BIT(1) > +# define DSI1_CTRL_DISABLE_DISP_ECCC BIT(1) > +# define DSI0_CTRL_CTRL0 BIT(0) > +# define DSI1_CTRL_EN BIT(0) > +# define DSI0_CTRL_RESET_FIFOS (DSI_CTRL_CLR_LDF | \ > + DSI0_CTRL_CLR_PBCF | \ > + DSI0_CTRL_CLR_CPBCF | \ > + DSI0_CTRL_CLR_PDF | \ > + DSI0_CTRL_CLR_CDF) > +# define DSI1_CTRL_RESET_FIFOS (DSI_CTRL_CLR_LDF | \ > + DSI1_CTRL_CLR_RXF | \ > + DSI1_CTRL_CLR_PDF | \ > + DSI1_CTRL_CLR_CDF) > + > +#define DSI1_TXPKT2C 0x0c > +#define DSI1_TXPKT2H 0x10 > +#define DSI1_TXPKT_PIX_FIFO 0x20 > +#define DSI1_RXPKT_FIFO 0x24 > +#define DSI1_DISP0_CTRL 0x28 > +#define DSI1_INT_STAT 0x30 > +#define DSI1_INT_EN 0x34 > +/* State reporting bits. These mostly behave like INT_STAT, where > + * writing a 1 clears the bit. > + */ > +#define DSI1_STAT 0x38 > +# define DSI1_STAT_PHY_D3_ULPS BIT(31) > +# define DSI1_STAT_PHY_D3_STOP BIT(30) > +# define DSI1_STAT_PHY_D2_ULPS BIT(29) > +# define DSI1_STAT_PHY_D2_STOP BIT(28) > +# define DSI1_STAT_PHY_D1_ULPS BIT(27) > +# define DSI1_STAT_PHY_D1_STOP BIT(26) > +# define DSI1_STAT_PHY_D0_ULPS BIT(25) > +# define DSI1_STAT_PHY_D0_STOP BIT(24) > +# define DSI1_STAT_FIFO_ERR BIT(23) > +# define DSI1_STAT_PHY_RXLPDT BIT(22) > +# define DSI1_STAT_PHY_RXTRIG BIT(21) > +# define DSI1_STAT_PHY_D0_LPDT BIT(20) > +/* Set when in forward direction */ > +# define DSI1_STAT_PHY_DIR BIT(19) > +# define DSI1_STAT_PHY_CLOCK_ULPS BIT(18) > +# define DSI1_STAT_PHY_CLOCK_HS BIT(17) > +# define DSI1_STAT_PHY_CLOCK_STOP BIT(16) > +# define DSI1_STAT_PR_TO BIT(15) > +# define DSI1_STAT_TA_TO BIT(14) > +# define DSI1_STAT_LPRX_TO BIT(13) > +# define DSI1_STAT_HSTX_TO BIT(12) > +# define DSI1_STAT_ERR_CONT_LP1 BIT(11) > +# define DSI1_STAT_ERR_CONT_LP0 BIT(10) > +# define DSI1_STAT_ERR_CONTROL BIT(9) > +# define DSI1_STAT_ERR_SYNC_ESC BIT(8) > +# define DSI1_STAT_RXPKT2 BIT(7) > +# define DSI1_STAT_RXPKT1 BIT(6) > +# define DSI1_STAT_TXPKT2_BUSY BIT(5) > +# define DSI1_STAT_TXPKT2_DONE BIT(4) > +# define DSI1_STAT_TXPKT2_END BIT(3) > +# define DSI1_STAT_TXPKT1_BUSY BIT(2) > +# define DSI1_STAT_TXPKT1_DONE BIT(1) > +# define DSI1_STAT_TXPKT1_END BIT(0) > + > +#define DSI1_HSTX_TO_CNT 0x3c > +#define DSI1_LPRX_TO_CNT 0x40 > +#define DSI1_TA_TO_CNT 0x44 > +#define DSI1_PR_TO_CNT 0x48 > +#define DSI1_PHYC 0x4c > + > +#define DSI1_HS_CLT0 0x50 > +# define DSI_HS_CLT0_CZERO_MASK VC4_MASK(26, 18) > +# define DSI_HS_CLT0_CZERO_SHIFT 18 > +# define DSI_HS_CLT0_CPRE_MASK VC4_MASK(17, 9) > +# define DSI_HS_CLT0_CPRE_SHIFT 9 > +# define DSI_HS_CLT0_CPREP_MASK VC4_MASK(8, 0) > +# define DSI_HS_CLT0_CPREP_SHIFT 0 > + > +#define DSI1_HS_CLT1 0x54 > +# define DSI_HS_CLT1_CTRAIL_MASK VC4_MASK(17, 9) > +# define DSI_HS_CLT1_CTRAIL_SHIFT 9 > +# define DSI_HS_CLT1_CPOST_MASK VC4_MASK(8, 0) > +# define DSI_HS_CLT1_CPOST_SHIFT 0 > + > +#define DSI1_HS_CLT2 0x58 > +# define DSI_HS_CLT2_WUP_MASK VC4_MASK(23, 0) > +# define DSI_HS_CLT2_WUP_SHIFT 0 > + > +#define DSI1_HS_DLT3 0x5c > +# define DSI_HS_DLT3_EXIT_MASK VC4_MASK(26, 18) > +# define DSI_HS_DLT3_EXIT_SHIFT 18 > +# define DSI_HS_DLT3_ZERO_MASK VC4_MASK(17, 9) > +# define DSI_HS_DLT3_ZERO_SHIFT 9 > +# define DSI_HS_DLT3_PRE_MASK VC4_MASK(8, 0) > +# define DSI_HS_DLT3_PRE_SHIFT 0 > + > +#define DSI1_HS_DLT4 0x60 > +# define DSI_HS_DLT4_ANLAT_MASK VC4_MASK(22, 18) > +# define DSI_HS_DLT4_ANLAT_SHIFT 18 > +# define DSI_HS_DLT4_TRAIL_MASK VC4_MASK(17, 9) > +# define DSI_HS_DLT4_TRAIL_SHIFT 9 > +# define DSI_HS_DLT4_LPX_MASK VC4_MASK(8, 0) > +# define DSI_HS_DLT4_LPX_SHIFT 0 > + > +#define DSI1_HS_DLT5 0x64 > +# define DSI_HS_DLT5_INIT_MASK VC4_MASK(23, 0) > +# define DSI_HS_DLT5_INIT_SHIFT 0 > + > +#define DSI1_HS_DLT6 0x68 > +# define DSI_HS_DLT6_TA_GET_MASK VC4_MASK(31, 24) > +# define DSI_HS_DLT6_TA_GET_SHIFT 24 > +# define DSI_HS_DLT6_TA_SURE_MASK VC4_MASK(23, 16) > +# define DSI_HS_DLT6_TA_SURE_SHIFT 16 > +# define DSI_HS_DLT6_TA_GO_MASK VC4_MASK(15, 8) > +# define DSI_HS_DLT6_TA_GO_SHIFT 8 > +# define DSI_HS_DLT6_LP_LPX_MASK VC4_MASK(7, 0) > +# define DSI_HS_DLT6_LP_LPX_SHIFT 0 > + > +#define DSI1_HS_DLT7 0x6c > +# define DSI_HS_DLT7_LP_WUP_MASK VC4_MASK(23, 0) > +# define DSI_HS_DLT7_LP_WUP_SHIFT 0 > + > +#define DSI1_PHY_AFEC0 0x70 > + > +#define DSI1_PHY_AFEC1 0x74 > +# define DSI1_PHY_AFEC1_ACTRL_DLANE3_MASK VC4_MASK(19, 16) > +# define DSI1_PHY_AFEC1_ACTRL_DLANE3_SHIFT 16 > +# define DSI1_PHY_AFEC1_ACTRL_DLANE2_MASK VC4_MASK(15, 12) > +# define DSI1_PHY_AFEC1_ACTRL_DLANE2_SHIFT 12 > +# define DSI1_PHY_AFEC1_ACTRL_DLANE1_MASK VC4_MASK(11, 8) > +# define DSI1_PHY_AFEC1_ACTRL_DLANE1_SHIFT 8 > +# define DSI1_PHY_AFEC1_ACTRL_DLANE0_MASK VC4_MASK(7, 4) > +# define DSI1_PHY_AFEC1_ACTRL_DLANE0_SHIFT 4 > +# define DSI1_PHY_AFEC1_ACTRL_CLANE_MASK VC4_MASK(3, 0) > +# define DSI1_PHY_AFEC1_ACTRL_CLANE_SHIFT 0 > + > +#define DSI1_TST_SEL 0x78 > +#define DSI1_TST_MON 0x7c > +#define DSI1_PHY_TST1 0x80 > +#define DSI1_PHY_TST2 0x84 > +#define DSI1_PHY_FIFO_STAT 0x88 > +/* Actually, all registers in the range that aren't otherwise claimed > + * will return the ID. > + */ > +#define DSI1_ID 0x8c > + > +/* General DSI hardware state. */ > +struct vc4_dsi { > + struct platform_device *pdev; > + > + struct mipi_dsi_host dsi_host; > + struct drm_encoder *encoder; > + struct drm_connector *connector; > + struct drm_panel *panel; > + > + void __iomem *regs; > + > + struct dma_chan *reg_dma_chan; > + dma_addr_t reg_dma_paddr; > + u32 *reg_dma_mem; > + dma_addr_t reg_paddr; > + > + /* Whether we're on bcm2835's DSI0 or DSI1. */ > + int port; > + > + /* DSI channel for the panel we're connected to. */ > + u32 channel; > + u32 lanes; > + enum mipi_dsi_pixel_format format; > + u32 mode_flags; > + > + /* Input clock from CPRMAN to the digital PHY, for the DSI > + * escape clock. > + */ > + struct clk *escape_clock; > + > + /* Input clock to the analog PHY, used to generate the DSI bit > + * clock. > + */ > + struct clk *pll_phy_clock; > + > + /* HS Clocks generated within the DSI analog PHY. */ > + struct clk_fixed_factor phy_clocks[3]; > + > + struct clk_onecell_data clk_onecell; > + > + /* Pixel clock output to the pixelvalve, generated from the HS > + * clock. > + */ > + struct clk *pixel_clock; > + > + struct completion xfer_completion; > + int xfer_result; > +}; > + > +#define host_to_dsi(host) container_of(host, struct vc4_dsi, dsi_host) > + > +static inline void > +dsi_dma_workaround_write(struct vc4_dsi *dsi, u32 offset, u32 val) > +{ > + struct dma_chan *chan = dsi->reg_dma_chan; > + struct dma_async_tx_descriptor *tx; > + dma_cookie_t cookie; > + int ret; > + > + /* DSI0 should be able to write normally. */ > + if (!chan) { > + writel(val, dsi->regs + offset); > + return; > + } > + > + *dsi->reg_dma_mem = val; > + > + tx = chan->device->device_prep_dma_memcpy(chan, > + dsi->reg_paddr + offset, > + dsi->reg_dma_paddr, > + 4, 0); > + if (!tx) { > + DRM_ERROR("Failed to set up DMA register write\n"); > + return; > + } > + > + cookie = tx->tx_submit(tx); > + ret = dma_submit_error(cookie); > + if (ret) { > + DRM_ERROR("Failed to submit DMA: %d\n", ret); > + return; > + } > + ret = dma_sync_wait(chan, cookie); > + if (ret) > + DRM_ERROR("Failed to wait for DMA: %d\n", ret); > +} > + > +#define DSI_READ(offset) readl(dsi->regs + (offset)) > +#define DSI_WRITE(offset, val) dsi_dma_workaround_write(dsi, offset, val) > +#define DSI_PORT_READ(offset) \ > + DSI_READ(dsi->port ? DSI1_##offset : DSI0_##offset) > +#define DSI_PORT_WRITE(offset, val) \ > + DSI_WRITE(dsi->port ? DSI1_##offset : DSI0_##offset, val) > +#define DSI_PORT_BIT(bit) (dsi->port ? DSI1_##bit : DSI0_##bit) > + > +/* VC4 DSI encoder KMS struct */ > +struct vc4_dsi_encoder { > + struct vc4_encoder base; > + struct vc4_dsi *dsi; > +}; > + > +static inline struct vc4_dsi_encoder * > +to_vc4_dsi_encoder(struct drm_encoder *encoder) > +{ > + return container_of(encoder, struct vc4_dsi_encoder, base.base); > +} > + > +/* VC4 DSI connector KMS struct */ > +struct vc4_dsi_connector { > + struct drm_connector base; > + struct vc4_dsi *dsi; > +}; > + > +static inline struct vc4_dsi_connector * > +to_vc4_dsi_connector(struct drm_connector *connector) > +{ > + return container_of(connector, struct vc4_dsi_connector, base); > +} > + > +#define DSI_REG(reg) { reg, #reg } > +static const struct { > + u32 reg; > + const char *name; > +} dsi0_regs[] = { > + DSI_REG(DSI0_CTRL), > + DSI_REG(DSI0_STAT), > + DSI_REG(DSI0_HSTX_TO_CNT), > + DSI_REG(DSI0_LPRX_TO_CNT), > + DSI_REG(DSI0_TA_TO_CNT), > + DSI_REG(DSI0_PR_TO_CNT), > + DSI_REG(DSI0_DISP0_CTRL), > + DSI_REG(DSI0_DISP1_CTRL), > + DSI_REG(DSI0_INT_STAT), > + DSI_REG(DSI0_INT_EN), > + DSI_REG(DSI0_PHYC), > + DSI_REG(DSI0_HS_CLT0), > + DSI_REG(DSI0_HS_CLT1), > + DSI_REG(DSI0_HS_CLT2), > + DSI_REG(DSI0_HS_DLT3), > + DSI_REG(DSI0_HS_DLT4), > + DSI_REG(DSI0_HS_DLT5), > + DSI_REG(DSI0_HS_DLT6), > + DSI_REG(DSI0_HS_DLT7), > + DSI_REG(DSI0_PHY_AFEC0), > + DSI_REG(DSI0_PHY_AFEC1), > + DSI_REG(DSI0_ID), > +}; > + > +static const struct { > + u32 reg; > + const char *name; > +} dsi1_regs[] = { > + DSI_REG(DSI1_CTRL), > + DSI_REG(DSI1_STAT), > + DSI_REG(DSI1_HSTX_TO_CNT), > + DSI_REG(DSI1_LPRX_TO_CNT), > + DSI_REG(DSI1_TA_TO_CNT), > + DSI_REG(DSI1_PR_TO_CNT), > + DSI_REG(DSI1_DISP0_CTRL), > + DSI_REG(DSI1_DISP1_CTRL), > + DSI_REG(DSI1_INT_STAT), > + DSI_REG(DSI1_INT_EN), > + DSI_REG(DSI1_PHYC), > + DSI_REG(DSI1_HS_CLT0), > + DSI_REG(DSI1_HS_CLT1), > + DSI_REG(DSI1_HS_CLT2), > + DSI_REG(DSI1_HS_DLT3), > + DSI_REG(DSI1_HS_DLT4), > + DSI_REG(DSI1_HS_DLT5), > + DSI_REG(DSI1_HS_DLT6), > + DSI_REG(DSI1_HS_DLT7), > + DSI_REG(DSI1_PHY_AFEC0), > + DSI_REG(DSI1_PHY_AFEC1), > + DSI_REG(DSI1_ID), > +}; > + > +static void vc4_dsi_dump_regs(struct vc4_dsi *dsi) > +{ > + int i; > + > + if (dsi->port == 0) { > + for (i = 0; i < ARRAY_SIZE(dsi0_regs); i++) { > + DRM_INFO("0x%04x (%s): 0x%08x\n", > + dsi0_regs[i].reg, dsi0_regs[i].name, > + DSI_READ(dsi0_regs[i].reg)); > + } > + } else { > + for (i = 0; i < ARRAY_SIZE(dsi1_regs); i++) { > + DRM_INFO("0x%04x (%s): 0x%08x\n", > + dsi1_regs[i].reg, dsi1_regs[i].name, > + DSI_READ(dsi1_regs[i].reg)); > + } > + } > +} > + > +#ifdef CONFIG_DEBUG_FS > +int vc4_dsi_debugfs_regs(struct seq_file *m, void *unused) > +{ > + struct drm_info_node *node = (struct drm_info_node *)m->private; > + struct drm_device *drm = node->minor->dev; > + struct vc4_dev *vc4 = to_vc4_dev(drm); > + int dsi_index = (uintptr_t)node->info_ent->data; > + struct vc4_dsi *dsi = (dsi_index == 1 ? vc4->dsi1 : NULL); > + int i; > + > + if (!dsi) > + return 0; > + > + if (dsi->port == 0) { > + for (i = 0; i < ARRAY_SIZE(dsi0_regs); i++) { > + seq_printf(m, "0x%04x (%s): 0x%08x\n", > + dsi0_regs[i].reg, dsi0_regs[i].name, > + DSI_READ(dsi0_regs[i].reg)); > + } > + } else { > + for (i = 0; i < ARRAY_SIZE(dsi1_regs); i++) { > + seq_printf(m, "0x%04x (%s): 0x%08x\n", > + dsi1_regs[i].reg, dsi1_regs[i].name, > + DSI_READ(dsi1_regs[i].reg)); > + } > + } > + > + return 0; > +} > +#endif > + > +static enum drm_connector_status > +vc4_dsi_connector_detect(struct drm_connector *connector, bool force) > +{ > + struct vc4_dsi_connector *vc4_connector = > + to_vc4_dsi_connector(connector); > + struct vc4_dsi *dsi = vc4_connector->dsi; > + > + if (dsi->panel) > + return connector_status_connected; > + else > + return connector_status_disconnected; > +} > + > +static void vc4_dsi_connector_destroy(struct drm_connector *connector) > +{ > + drm_connector_unregister(connector); > + drm_connector_cleanup(connector); > +} > + > +static int vc4_dsi_connector_get_modes(struct drm_connector *connector) > +{ > + struct vc4_dsi_connector *vc4_connector = > + to_vc4_dsi_connector(connector); > + struct vc4_dsi *dsi = vc4_connector->dsi; > + > + if (dsi->panel) > + return drm_panel_get_modes(dsi->panel); > + > + return 0; > +} I'm still hoping that somewhen someone adds a drm_panel * pointer to drm_connector and writes the glue functions in a helper library so we could garbage-collect all our copies of the same stuff implementing ->detect and ->get_modes ... > + > +static const struct drm_connector_funcs vc4_dsi_connector_funcs = { > + .dpms = drm_atomic_helper_connector_dpms, > + .detect = vc4_dsi_connector_detect, > + .fill_modes = drm_helper_probe_single_connector_modes, > + .destroy = vc4_dsi_connector_destroy, > + .reset = drm_atomic_helper_connector_reset, > + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, > + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, > +}; > + > +static const struct drm_connector_helper_funcs vc4_dsi_connector_helper_funcs = { > + .get_modes = vc4_dsi_connector_get_modes, > +}; > + > +static struct drm_connector *vc4_dsi_connector_init(struct drm_device *dev, > + struct vc4_dsi *dsi) > +{ > + struct drm_connector *connector = NULL; > + struct vc4_dsi_connector *dsi_connector; > + int ret = 0; > + > + dsi_connector = devm_kzalloc(dev->dev, sizeof(*dsi_connector), > + GFP_KERNEL); > + if (!dsi_connector) { > + ret = -ENOMEM; > + goto fail; > + } > + connector = &dsi_connector->base; > + > + dsi_connector->dsi = dsi; > + > + drm_connector_init(dev, connector, &vc4_dsi_connector_funcs, > + DRM_MODE_CONNECTOR_DSI); > + drm_connector_helper_add(connector, &vc4_dsi_connector_helper_funcs); > + > + connector->polled = 0; > + connector->interlace_allowed = 0; > + connector->doublescan_allowed = 0; > + > + drm_mode_connector_attach_encoder(connector, dsi->encoder); > + > + return connector; > + > +fail: > + if (connector) > + vc4_dsi_connector_destroy(connector); > + > + return ERR_PTR(ret); > +} > + > +static void vc4_dsi_encoder_destroy(struct drm_encoder *encoder) > +{ > + drm_encoder_cleanup(encoder); > +} > + > +static const struct drm_encoder_funcs vc4_dsi_encoder_funcs = { > + .destroy = vc4_dsi_encoder_destroy, > +}; > + > +static void vc4_dsi_latch_ulps(struct vc4_dsi *dsi, bool latch) > +{ > + u32 afec0 = DSI_PORT_READ(PHY_AFEC0); > + > + if (latch) > + afec0 |= DSI_PORT_BIT(PHY_AFEC0_LATCH_ULPS); > + else > + afec0 &= ~DSI_PORT_BIT(PHY_AFEC0_LATCH_ULPS); > + > + DSI_PORT_WRITE(PHY_AFEC0, afec0); > +} > + > +/* Enters or exits Ultra Low Power State. */ > +static void vc4_dsi_ulps(struct vc4_dsi *dsi, bool ulps) > +{ > + bool continuous = dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS; > + u32 phyc_ulps = ((continuous ? DSI_PORT_BIT(PHYC_CLANE_ULPS) : 0) | > + DSI_PHYC_DLANE0_ULPS | > + (dsi->lanes > 1 ? DSI_PHYC_DLANE1_ULPS : 0) | > + (dsi->lanes > 2 ? DSI_PHYC_DLANE2_ULPS : 0) | > + (dsi->lanes > 3 ? DSI_PHYC_DLANE3_ULPS : 0)); > + u32 stat_ulps = ((continuous ? DSI1_STAT_PHY_CLOCK_ULPS : 0) | > + DSI1_STAT_PHY_D0_ULPS | > + (dsi->lanes > 1 ? DSI1_STAT_PHY_D1_ULPS : 0) | > + (dsi->lanes > 2 ? DSI1_STAT_PHY_D2_ULPS : 0) | > + (dsi->lanes > 3 ? DSI1_STAT_PHY_D3_ULPS : 0)); > + u32 stat_stop = ((continuous ? DSI1_STAT_PHY_CLOCK_STOP : 0) | > + DSI1_STAT_PHY_D0_STOP | > + (dsi->lanes > 1 ? DSI1_STAT_PHY_D1_STOP : 0) | > + (dsi->lanes > 2 ? DSI1_STAT_PHY_D2_STOP : 0) | > + (dsi->lanes > 3 ? DSI1_STAT_PHY_D3_STOP : 0)); > + int ret; > + > + DSI_PORT_WRITE(STAT, stat_ulps); > + DSI_PORT_WRITE(PHYC, DSI_PORT_READ(PHYC) | phyc_ulps); > + ret = wait_for((DSI_PORT_READ(STAT) & stat_ulps) == stat_ulps, 200); > + if (ret) { > + dev_warn(&dsi->pdev->dev, > + "Timeout waiting for DSI ULPS entry: STAT 0x%08x", > + DSI_PORT_READ(STAT)); > + DSI_PORT_WRITE(PHYC, DSI_PORT_READ(PHYC) & ~phyc_ulps); > + vc4_dsi_latch_ulps(dsi, false); > + return; > + } > + > + /* The DSI module can't be disabled while the module is > + * generating ULPS state. So, to be able to disable the > + * module, we have the AFE latch the ULPS state and continue > + * on to having the module enter STOP. > + */ > + vc4_dsi_latch_ulps(dsi, ulps); > + > + DSI_PORT_WRITE(STAT, stat_stop); > + DSI_PORT_WRITE(PHYC, DSI_PORT_READ(PHYC) & ~phyc_ulps); > + ret = wait_for((DSI_PORT_READ(STAT) & stat_stop) == stat_stop, 200); > + if (ret) { > + dev_warn(&dsi->pdev->dev, > + "Timeout waiting for DSI STOP entry: STAT 0x%08x", > + DSI_PORT_READ(STAT)); > + DSI_PORT_WRITE(PHYC, DSI_PORT_READ(PHYC) & ~phyc_ulps); > + return; > + } > +} > + > +static u32 > +dsi_hs_timing(u32 ui_ns, u32 ns, u32 ui) > +{ > + /* The HS timings have to be rounded up to a multiple of 8 > + * because we're using the byte clock. > + */ > + return roundup(ui + DIV_ROUND_UP(ns, ui_ns), 8); > +} > + > +/* ESC always runs at 100Mhz. */ > +#define ESC_TIME_NS 10 > + > +static u32 > +dsi_esc_timing(u32 ns) > +{ > + return DIV_ROUND_UP(ns, ESC_TIME_NS); > +} > + > +static void vc4_dsi_encoder_disable(struct drm_encoder *encoder) > +{ > + struct vc4_dsi_encoder *vc4_encoder = to_vc4_dsi_encoder(encoder); > + struct vc4_dsi *dsi = vc4_encoder->dsi; > + struct device *dev = &dsi->pdev->dev; > + > + drm_panel_disable(dsi->panel); > + > + vc4_dsi_ulps(dsi, true); > + > + drm_panel_unprepare(dsi->panel); > + > + clk_disable_unprepare(dsi->pll_phy_clock); > + clk_disable_unprepare(dsi->escape_clock); > + clk_disable_unprepare(dsi->pixel_clock); > + > + pm_runtime_put(dev); > +} > + > +static void vc4_dsi_encoder_enable(struct drm_encoder *encoder) > +{ > + struct drm_display_mode *mode = &encoder->crtc->mode; > + struct vc4_dsi_encoder *vc4_encoder = to_vc4_dsi_encoder(encoder); > + struct vc4_dsi *dsi = vc4_encoder->dsi; > + struct device *dev = &dsi->pdev->dev; > + u32 format = 0, divider = 0; > + bool debug_dump_regs = false; > + unsigned long hs_clock; > + u32 ui_ns; > + /* Minimum LP state duration in escape clock cycles. */ > + u32 lpx = dsi_esc_timing(60); > + unsigned long pixel_clock_hz = mode->clock * 1000; > + unsigned long dsip_clock; > + unsigned long phy_clock; > + int ret; > + > + ret = pm_runtime_get_sync(dev); > + if (ret) { > + DRM_ERROR("Failed to runtime PM enable on DSI%d\n", dsi->port); > + return; > + } > + > + ret = drm_panel_prepare(dsi->panel); > + if (ret) { > + DRM_ERROR("Panel failed to prepare\n"); > + return; > + } > + > + if (debug_dump_regs) { > + DRM_INFO("DSI regs before:\n"); > + vc4_dsi_dump_regs(dsi); > + } > + > + switch (dsi->format) { > + case MIPI_DSI_FMT_RGB888: > + format = DSI_PFORMAT_RGB888; > + divider = 24 / dsi->lanes; > + break; > + case MIPI_DSI_FMT_RGB666: > + format = DSI_PFORMAT_RGB666; > + divider = 24 / dsi->lanes; > + break; > + case MIPI_DSI_FMT_RGB666_PACKED: > + format = DSI_PFORMAT_RGB666_PACKED; > + divider = 18 / dsi->lanes; > + break; > + case MIPI_DSI_FMT_RGB565: > + format = DSI_PFORMAT_RGB565; > + divider = 16 / dsi->lanes; > + break; > + } > + > + phy_clock = pixel_clock_hz * divider; > + ret = clk_set_rate(dsi->pll_phy_clock, phy_clock); > + if (ret) { > + dev_err(&dsi->pdev->dev, > + "Failed to set phy clock to %ld: %d\n", phy_clock, ret); > + } > + > + /* Reset the DSI and all its fifos. */ > + DSI_PORT_WRITE(CTRL, > + DSI_CTRL_SOFT_RESET_CFG | > + DSI_PORT_BIT(CTRL_RESET_FIFOS)); > + > + DSI_PORT_WRITE(CTRL, > + DSI_CTRL_HSDT_EOT_DISABLE | > + DSI_CTRL_RX_LPDT_EOT_DISABLE); > + > + /* Clear all stat bits so we see what has happened during enable. */ > + DSI_PORT_WRITE(STAT, DSI_PORT_READ(STAT)); > + > + /* Set AFE CTR00/CTR1 to release powerdown of analog. */ > + if (dsi->port == 0) { > + u32 afec0 = (VC4_SET_FIELD(7, DSI_PHY_AFEC0_PTATADJ) | > + VC4_SET_FIELD(7, DSI_PHY_AFEC0_CTATADJ)); > + > + if (dsi->lanes < 2) > + afec0 |= DSI0_PHY_AFEC0_PD_DLANE1; > + > + if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO)) > + afec0 |= DSI0_PHY_AFEC0_RESET; > + > + DSI_PORT_WRITE(PHY_AFEC0, afec0); > + > + DSI_PORT_WRITE(PHY_AFEC1, > + VC4_SET_FIELD(6, DSI0_PHY_AFEC1_IDR_DLANE1) | > + VC4_SET_FIELD(6, DSI0_PHY_AFEC1_IDR_DLANE0) | > + VC4_SET_FIELD(6, DSI0_PHY_AFEC1_IDR_CLANE)); > + } else { > + u32 afec0 = (VC4_SET_FIELD(7, DSI_PHY_AFEC0_PTATADJ) | > + VC4_SET_FIELD(7, DSI_PHY_AFEC0_CTATADJ) | > + VC4_SET_FIELD(6, DSI1_PHY_AFEC0_IDR_CLANE) | > + VC4_SET_FIELD(6, DSI1_PHY_AFEC0_IDR_DLANE0) | > + VC4_SET_FIELD(6, DSI1_PHY_AFEC0_IDR_DLANE1) | > + VC4_SET_FIELD(6, DSI1_PHY_AFEC0_IDR_DLANE2) | > + VC4_SET_FIELD(6, DSI1_PHY_AFEC0_IDR_DLANE3)); > + > + if (dsi->lanes < 4) > + afec0 |= DSI1_PHY_AFEC0_PD_DLANE3; > + if (dsi->lanes < 3) > + afec0 |= DSI1_PHY_AFEC0_PD_DLANE2; > + if (dsi->lanes < 2) > + afec0 |= DSI1_PHY_AFEC0_PD_DLANE1; > + > + afec0 |= DSI1_PHY_AFEC0_RESET; > + > + DSI_PORT_WRITE(PHY_AFEC0, afec0); > + > + DSI_PORT_WRITE(PHY_AFEC1, 0); > + > + /* AFEC reset hold time */ > + mdelay(1); > + } > + > + ret = clk_prepare_enable(dsi->escape_clock); > + if (ret) { > + DRM_ERROR("Failed to turn on DSI escape clock: %d\n", ret); > + return; > + } > + > + ret = clk_prepare_enable(dsi->pll_phy_clock); > + if (ret) { > + DRM_ERROR("Failed to turn on DSI PLL: %d\n", ret); > + return; > + } > + > + hs_clock = clk_get_rate(dsi->pll_phy_clock); > + > + /* Yes, we set the DSI0P/DSI1P pixel clock to the byte rate, > + * not the pixel clock rate. DSIxP take from the APHY's byte, > + * DDR2, or DDR4 clock (we use byte) and feed into the PV at > + * that rate. Separately, a value derived from PIX_CLK_DIV > + * and HS_CLKC is fed into the PV to divide down to the actual > + * pixel clock for pushing pixels into DSI. > + */ > + dsip_clock = phy_clock / 8; > + ret = clk_set_rate(dsi->pixel_clock, dsip_clock); > + if (ret) { > + dev_err(dev, "Failed to set pixel clock to %ldHz: %d\n", > + dsip_clock, ret); > + } > + > + ret = clk_prepare_enable(dsi->pixel_clock); > + if (ret) { > + DRM_ERROR("Failed to turn on DSI pixel clock: %d\n", ret); > + return; > + } > + > + /* How many ns one DSI unit interval is. Note that the clock > + * is DDR, so there's an extra divide by 2. > + */ > + ui_ns = DIV_ROUND_UP(500000000, hs_clock); > + > + DSI_PORT_WRITE(HS_CLT0, > + VC4_SET_FIELD(dsi_hs_timing(ui_ns, 262, 0), > + DSI_HS_CLT0_CZERO) | > + VC4_SET_FIELD(dsi_hs_timing(ui_ns, 0, 8), > + DSI_HS_CLT0_CPRE) | > + VC4_SET_FIELD(dsi_hs_timing(ui_ns, 38, 0), > + DSI_HS_CLT0_CPREP)); > + > + DSI_PORT_WRITE(HS_CLT1, > + VC4_SET_FIELD(dsi_hs_timing(ui_ns, 60, 0), > + DSI_HS_CLT1_CTRAIL) | > + VC4_SET_FIELD(dsi_hs_timing(ui_ns, 60, 52), > + DSI_HS_CLT1_CPOST)); > + > + DSI_PORT_WRITE(HS_CLT2, > + VC4_SET_FIELD(dsi_hs_timing(ui_ns, 1000000, 0), > + DSI_HS_CLT2_WUP)); > + > + DSI_PORT_WRITE(HS_DLT3, > + VC4_SET_FIELD(dsi_hs_timing(ui_ns, 100, 0), > + DSI_HS_DLT3_EXIT) | > + VC4_SET_FIELD(dsi_hs_timing(ui_ns, 105, 6), > + DSI_HS_DLT3_ZERO) | > + VC4_SET_FIELD(dsi_hs_timing(ui_ns, 40, 4), > + DSI_HS_DLT3_PRE)); > + > + DSI_PORT_WRITE(HS_DLT4, > + VC4_SET_FIELD(dsi_hs_timing(ui_ns, lpx * ESC_TIME_NS, 0), > + DSI_HS_DLT4_LPX) | > + VC4_SET_FIELD(max(dsi_hs_timing(ui_ns, 0, 8), > + dsi_hs_timing(ui_ns, 60, 4)), > + DSI_HS_DLT4_TRAIL) | > + VC4_SET_FIELD(0, DSI_HS_DLT4_ANLAT)); > + > + DSI_PORT_WRITE(HS_DLT5, VC4_SET_FIELD(dsi_hs_timing(ui_ns, 1000, 5000), > + DSI_HS_DLT5_INIT)); > + > + DSI_PORT_WRITE(HS_DLT6, > + VC4_SET_FIELD(lpx * 5, DSI_HS_DLT6_TA_GET) | > + VC4_SET_FIELD(lpx, DSI_HS_DLT6_TA_SURE) | > + VC4_SET_FIELD(lpx * 4, DSI_HS_DLT6_TA_GO) | > + VC4_SET_FIELD(lpx, DSI_HS_DLT6_LP_LPX)); > + > + DSI_PORT_WRITE(HS_DLT7, > + VC4_SET_FIELD(dsi_esc_timing(1000000), > + DSI_HS_DLT7_LP_WUP)); > + > + DSI_PORT_WRITE(PHYC, > + DSI_PHYC_DLANE0_ENABLE | > + (dsi->lanes >= 2 ? DSI_PHYC_DLANE1_ENABLE : 0) | > + (dsi->lanes >= 3 ? DSI_PHYC_DLANE2_ENABLE : 0) | > + (dsi->lanes >= 4 ? DSI_PHYC_DLANE3_ENABLE : 0) | > + DSI_PORT_BIT(PHYC_CLANE_ENABLE) | > + ((dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) ? > + 0 : DSI_PORT_BIT(PHYC_HS_CLK_CONTINUOUS)) | > + (dsi->port == 0 ? > + VC4_SET_FIELD(lpx - 1, DSI0_PHYC_ESC_CLK_LPDT) : > + VC4_SET_FIELD(lpx - 1, DSI1_PHYC_ESC_CLK_LPDT))); > + > + DSI_PORT_WRITE(CTRL, > + DSI_PORT_READ(CTRL) | > + DSI_CTRL_CAL_BYTE); > + > + /* HS timeout in HS clock cycles: disabled. */ > + DSI_PORT_WRITE(HSTX_TO_CNT, 0); > + /* LP receive timeout in HS clocks. */ > + DSI_PORT_WRITE(LPRX_TO_CNT, 0xffffff); > + /* Bus turnaround timeout */ > + DSI_PORT_WRITE(TA_TO_CNT, 100000); > + /* Display reset sequence timeout */ > + DSI_PORT_WRITE(PR_TO_CNT, 100000); > + > + if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) { > + DSI_PORT_WRITE(DISP0_CTRL, > + VC4_SET_FIELD(divider, DSI_DISP0_PIX_CLK_DIV) | > + VC4_SET_FIELD(format, DSI_DISP0_PFORMAT) | > + VC4_SET_FIELD(DSI_DISP0_LP_STOP_PERFRAME, > + DSI_DISP0_LP_STOP_CTRL) | > + DSI_DISP0_ST_END | > + DSI_DISP0_ENABLE); > + } else { > + DSI_PORT_WRITE(DISP0_CTRL, > + DSI_DISP0_COMMAND_MODE | > + DSI_DISP0_ENABLE); > + } > + > + /* Set up DISP1 for transferring long command payloads through > + * the pixfifo. > + */ > + DSI_PORT_WRITE(DISP1_CTRL, > + VC4_SET_FIELD(DSI_DISP1_PFORMAT_32BIT_LE, > + DSI_DISP1_PFORMAT) | > + DSI_DISP1_ENABLE); > + > + /* Ungate the block. */ > + if (dsi->port == 0) > + DSI_PORT_WRITE(CTRL, DSI_PORT_READ(CTRL) | DSI0_CTRL_CTRL0); > + else > + DSI_PORT_WRITE(CTRL, DSI_PORT_READ(CTRL) | DSI1_CTRL_EN); > + > + /* Bring AFE out of reset. */ > + if (dsi->port == 0) { > + } else { > + DSI_PORT_WRITE(PHY_AFEC0, > + DSI_PORT_READ(PHY_AFEC0) & > + ~DSI1_PHY_AFEC0_RESET); > + } > + > + vc4_dsi_ulps(dsi, false); > + > + if (debug_dump_regs) { > + DRM_INFO("DSI regs after:\n"); > + vc4_dsi_dump_regs(dsi); > + } > + > + ret = drm_panel_enable(dsi->panel); > + if (ret) { > + DRM_ERROR("Panel failed to enable\n"); > + drm_panel_unprepare(dsi->panel); > + return; > + } > +} > + > +static ssize_t vc4_dsi_host_transfer(struct mipi_dsi_host *host, > + const struct mipi_dsi_msg *msg) > +{ > + struct vc4_dsi *dsi = host_to_dsi(host); > + struct mipi_dsi_packet packet; > + u32 pkth = 0, pktc = 0; > + int i, ret; > + bool is_long = mipi_dsi_packet_format_is_long(msg->type); > + u32 cmd_fifo_len = 0, pix_fifo_len = 0; > + > + mipi_dsi_create_packet(&packet, msg); > + > + pkth |= VC4_SET_FIELD(packet.header[0], DSI_TXPKT1H_BC_DT); > + pkth |= VC4_SET_FIELD(packet.header[1] | > + (packet.header[2] << 8), > + DSI_TXPKT1H_BC_PARAM); > + if (is_long) { > + /* Divide data across the various FIFOs we have available. > + * The command FIFO takes byte-oriented data, but is of > + * limited size. The pixel FIFO (never actually used for > + * pixel data in reality) is word oriented, and substantially > + * larger. So, we use the pixel FIFO for most of the data, > + * sending the residual bytes in the command FIFO at the start. > + * > + * With this arrangement, the command FIFO will never get full. > + */ I wondered whether this is something the dsi core should maybe optionally do, but doesn't seem to be a common pattern looking at existing transfer functions. > + if (packet.payload_length <= 16) { > + cmd_fifo_len = packet.payload_length; > + pix_fifo_len = 0; > + } else { > + cmd_fifo_len = (packet.payload_length % > + DSI_PIX_FIFO_WIDTH); > + pix_fifo_len = ((packet.payload_length - cmd_fifo_len) / > + DSI_PIX_FIFO_WIDTH); > + } > + > + WARN_ON_ONCE(pix_fifo_len >= DSI_PIX_FIFO_DEPTH); > + > + pkth |= VC4_SET_FIELD(cmd_fifo_len, DSI_TXPKT1H_BC_CMDFIFO); > + } > + > + if (msg->rx_len) { > + pktc |= VC4_SET_FIELD(DSI_TXPKT1C_CMD_CTRL_RX, > + DSI_TXPKT1C_CMD_CTRL); > + } else { > + pktc |= VC4_SET_FIELD(DSI_TXPKT1C_CMD_CTRL_TX, > + DSI_TXPKT1C_CMD_CTRL); > + } > + > + for (i = 0; i < cmd_fifo_len; i++) > + DSI_PORT_WRITE(TXPKT_CMD_FIFO, packet.payload[i]); > + for (i = 0; i < pix_fifo_len; i++) { > + const u8 *pix = packet.payload + cmd_fifo_len + i * 4; > + > + DSI_PORT_WRITE(TXPKT_PIX_FIFO, > + pix[0] | > + pix[1] << 8 | > + pix[2] << 16 | > + pix[3] << 24); > + } > + > + if (msg->flags & MIPI_DSI_MSG_USE_LPM) > + pktc |= DSI_TXPKT1C_CMD_MODE_LP; > + if (is_long) > + pktc |= DSI_TXPKT1C_CMD_TYPE_LONG; > + > + /* Send one copy of the packet. Larger repeats are used for pixel > + * data in command mode. > + */ > + pktc |= VC4_SET_FIELD(1, DSI_TXPKT1C_CMD_REPEAT); > + > + pktc |= DSI_TXPKT1C_CMD_EN; > + if (pix_fifo_len) { > + pktc |= VC4_SET_FIELD(DSI_TXPKT1C_DISPLAY_NO_SECONDARY, > + DSI_TXPKT1C_DISPLAY_NO); > + } else { > + pktc |= VC4_SET_FIELD(DSI_TXPKT1C_DISPLAY_NO_SHORT, > + DSI_TXPKT1C_DISPLAY_NO); > + } > + > + /* Enable the appropriate interrupt for the transfer completion. */ > + dsi->xfer_result = 0; > + reinit_completion(&dsi->xfer_completion); > + DSI_PORT_WRITE(INT_STAT, DSI1_INT_TXPKT1_DONE | DSI1_INT_PHY_DIR_RTF); > + if (msg->rx_len) { > + DSI_PORT_WRITE(INT_EN, (DSI1_INTERRUPTS_ALWAYS_ENABLED | > + DSI1_INT_PHY_DIR_RTF)); > + } else { > + DSI_PORT_WRITE(INT_EN, (DSI1_INTERRUPTS_ALWAYS_ENABLED | > + DSI1_INT_TXPKT1_DONE)); > + } > + > + /* Send the packet. */ > + DSI_PORT_WRITE(TXPKT1H, pkth); > + DSI_PORT_WRITE(TXPKT1C, pktc); > + > + if (!wait_for_completion_timeout(&dsi->xfer_completion, > + msecs_to_jiffies(1000))) { > + dev_err(&dsi->pdev->dev, "transfer interrupt wait timeout"); > + dev_err(&dsi->pdev->dev, "instat: 0x%08x\n", > + DSI_PORT_READ(INT_STAT)); > + ret = -ETIMEDOUT; > + } else { > + ret = dsi->xfer_result; > + } > + > + DSI_PORT_WRITE(INT_EN, DSI1_INTERRUPTS_ALWAYS_ENABLED); > + > + if (ret) > + goto reset_fifo_and_return; > + > + if (ret == 0 && msg->rx_len) { > + u32 rxpkt1h = DSI_PORT_READ(RXPKT1H); > + u8 *msg_rx = msg->rx_buf; > + > + if (rxpkt1h & DSI_RXPKT1H_PKT_TYPE_LONG) { > + u32 rxlen = VC4_GET_FIELD(rxpkt1h, > + DSI_RXPKT1H_BC_PARAM); > + > + if (rxlen != msg->rx_len) { > + DRM_ERROR("DSI returned %db, expecting %db\n", > + rxlen, (int)msg->rx_len); > + ret = -ENXIO; > + goto reset_fifo_and_return; > + } > + > + for (i = 0; i < msg->rx_len; i++) > + msg_rx[i] = DSI_READ(DSI1_RXPKT_FIFO); > + } else { > + /* FINISHME: Handle AWER */ > + > + msg_rx[0] = VC4_GET_FIELD(rxpkt1h, > + DSI_RXPKT1H_SHORT_0); > + if (msg->rx_len > 1) { > + msg_rx[1] = VC4_GET_FIELD(rxpkt1h, > + DSI_RXPKT1H_SHORT_1); > + } > + } > + } > + > + return ret; > + > +reset_fifo_and_return: > + DRM_ERROR("DSI transfer failed, resetting: %d\n", ret); > + > + DSI_PORT_WRITE(TXPKT1C, DSI_PORT_READ(TXPKT1C) & ~DSI_TXPKT1C_CMD_EN); > + udelay(1); > + DSI_PORT_WRITE(CTRL, > + DSI_PORT_READ(CTRL) | > + DSI_PORT_BIT(CTRL_RESET_FIFOS)); > + > + DSI_PORT_WRITE(TXPKT1C, 0); > + DSI_PORT_WRITE(INT_EN, DSI1_INTERRUPTS_ALWAYS_ENABLED); > + return ret; > +} > + > +static int vc4_dsi_host_attach(struct mipi_dsi_host *host, > + struct mipi_dsi_device *device) > +{ > + struct vc4_dsi *dsi = host_to_dsi(host); > + int ret = 0; > + > + dsi->lanes = device->lanes; > + dsi->channel = device->channel; > + dsi->format = device->format; > + dsi->mode_flags = device->mode_flags; > + > + if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO)) { > + dev_err(&dsi->pdev->dev, > + "Only VIDEO mode panels supported currently.\n"); > + return 0; > + } > + > + dsi->panel = of_drm_find_panel(device->dev.of_node); > + if (!dsi->panel) > + return 0; > + > + ret = drm_panel_attach(dsi->panel, dsi->connector); > + if (ret != 0) > + return ret; > + > + drm_helper_hpd_irq_event(dsi->connector->dev); > + > + return 0; > +} > + > +static int vc4_dsi_host_detach(struct mipi_dsi_host *host, > + struct mipi_dsi_device *device) > +{ > + struct vc4_dsi *dsi = host_to_dsi(host); > + > + if (dsi->panel) { > + int ret = drm_panel_detach(dsi->panel); > + > + if (ret) > + return ret; > + > + dsi->panel = NULL; > + > + drm_helper_hpd_irq_event(dsi->connector->dev); > + } > + > + return 0; > +} > + > +static const struct mipi_dsi_host_ops vc4_dsi_host_ops = { > + .attach = vc4_dsi_host_attach, > + .detach = vc4_dsi_host_detach, There seems to be a lot of cargo-culting going on with attach/detach, and I get a bit the feeling that refactoring this into a standard way to do it (including the of/dt boilerplate, with an eye towards standardizing the bindinds) would be good. Also, proper kerneldoc for these callbacks instead of the onelines (we can do multiline inline comments now, with formatting!) would be great. > + .transfer = vc4_dsi_host_transfer, hisilicon doesn't even have a transfer function, I guess it works by magic. > +}; > + > +static const struct drm_encoder_helper_funcs vc4_dsi_encoder_helper_funcs = { > + .disable = vc4_dsi_encoder_disable, > + .enable = vc4_dsi_encoder_enable, > +}; > + > +static const struct of_device_id vc4_dsi_dt_match[] = { > + { .compatible = "brcm,bcm2835-dsi1", (void *)(uintptr_t)1 }, > + {} > +}; > + > +static void dsi_handle_error(struct vc4_dsi *dsi, > + irqreturn_t *ret, u32 stat, u32 bit, > + const char *type) > +{ > + if (!(stat & bit)) > + return; > + > + DRM_ERROR("DSI%d: %s error\n", dsi->port, type); > + *ret = IRQ_HANDLED; > +} > + > +static irqreturn_t vc4_dsi_irq_handler(int irq, void *data) > +{ > + struct vc4_dsi *dsi = data; > + u32 stat = DSI_PORT_READ(INT_STAT); > + irqreturn_t ret = IRQ_NONE; > + > + DSI_PORT_WRITE(INT_STAT, stat); > + > + dsi_handle_error(dsi, &ret, stat, > + DSI1_INT_ERR_SYNC_ESC, "LPDT sync"); > + dsi_handle_error(dsi, &ret, stat, > + DSI1_INT_ERR_CONTROL, "data lane 0 sequence"); > + dsi_handle_error(dsi, &ret, stat, > + DSI1_INT_ERR_CONT_LP0, "LP0 contention"); > + dsi_handle_error(dsi, &ret, stat, > + DSI1_INT_ERR_CONT_LP1, "LP1 contention"); > + dsi_handle_error(dsi, &ret, stat, > + DSI1_INT_HSTX_TO, "HSTX timeout"); > + dsi_handle_error(dsi, &ret, stat, > + DSI1_INT_LPRX_TO, "LPRX timeout"); > + dsi_handle_error(dsi, &ret, stat, > + DSI1_INT_TA_TO, "turnaround timeout"); > + dsi_handle_error(dsi, &ret, stat, > + DSI1_INT_PR_TO, "peripheral reset timeout"); > + > + if (stat & (DSI1_INT_TXPKT1_DONE | DSI1_INT_PHY_DIR_RTF)) { > + complete(&dsi->xfer_completion); > + ret = IRQ_HANDLED; > + } else if (stat & DSI1_INT_HSTX_TO) { > + complete(&dsi->xfer_completion); > + dsi->xfer_result = -ETIMEDOUT; > + ret = IRQ_HANDLED; > + } > + > + return ret; > +} > + > +/** > + * Exposes clocks generated by the analog PHY that are consumed by > + * CPRMAN (clk-bcm2835.c). > + */ > +static int > +vc4_dsi_init_phy_clocks(struct vc4_dsi *dsi) > +{ > + struct device *dev = &dsi->pdev->dev; > + const char *parent_name = __clk_get_name(dsi->pll_phy_clock); > + static const struct { > + const char *dsi0_name, *dsi1_name; > + int div; > + } phy_clocks[] = { > + { "dsi0_byte", "dsi1_byte", 8 }, > + { "dsi0_ddr2", "dsi1_ddr2", 4 }, > + { "dsi0_ddr", "dsi1_ddr", 2 }, > + }; > + int i; > + > + dsi->clk_onecell.clk_num = ARRAY_SIZE(phy_clocks); > + dsi->clk_onecell.clks = devm_kcalloc(dev, > + dsi->clk_onecell.clk_num, > + sizeof(*dsi->clk_onecell.clks), > + GFP_KERNEL); > + if (!dsi->clk_onecell.clks) > + return -ENOMEM; > + > + for (i = 0; i < ARRAY_SIZE(phy_clocks); i++) { > + struct clk_fixed_factor *fix = &dsi->phy_clocks[i]; > + struct clk_init_data init; > + struct clk *clk; > + > + /* We just use core fixed factor clock ops for the PHY > + * clocks. The clocks are actually gated by the > + * PHY_AFEC0_DDRCLK_EN bits, which we should be > + * setting if we use the DDR/DDR2 clocks. However, > + * vc4_dsi_encoder_enable() is setting up both AFEC0, > + * setting both our parent DSI PLL's rate and this > + * clock's rate, so it knows if DDR/DDR2 are going to > + * be used and could enable the gates itself. > + */ > + fix->mult = 1; > + fix->div = phy_clocks[i].div; > + fix->hw.init = &init; > + > + memset(&init, 0, sizeof(init)); > + init.parent_names = &parent_name; > + init.num_parents = 1; > + if (dsi->port == 1) > + init.name = phy_clocks[i].dsi1_name; > + else > + init.name = phy_clocks[i].dsi0_name; > + init.ops = &clk_fixed_factor_ops; > + init.flags = CLK_IS_BASIC; > + > + clk = devm_clk_register(dev, &fix->hw); > + if (IS_ERR(clk)) > + return PTR_ERR(clk); > + > + dsi->clk_onecell.clks[i] = clk; > + } > + > + return of_clk_add_provider(dev->of_node, > + of_clk_src_onecell_get, > + &dsi->clk_onecell); > +} > + > +static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) > +{ > + struct platform_device *pdev = to_platform_device(dev); > + struct drm_device *drm = dev_get_drvdata(master); > + struct vc4_dev *vc4 = to_vc4_dev(drm); > + struct vc4_dsi *dsi; > + struct vc4_dsi_encoder *vc4_dsi_encoder; > + const struct of_device_id *match; > + dma_cap_mask_t dma_mask; > + int ret; > + > + dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL); > + if (!dsi) > + return -ENOMEM; > + > + match = of_match_device(vc4_dsi_dt_match, dev); > + if (!match) > + return -ENODEV; > + > + dsi->port = (uintptr_t)match->data; > + > + vc4_dsi_encoder = devm_kzalloc(dev, sizeof(*vc4_dsi_encoder), > + GFP_KERNEL); > + if (!vc4_dsi_encoder) > + return -ENOMEM; > + vc4_dsi_encoder->base.type = VC4_ENCODER_TYPE_DSI1; > + vc4_dsi_encoder->dsi = dsi; > + dsi->encoder = &vc4_dsi_encoder->base.base; > + > + dsi->pdev = pdev; > + dsi->regs = vc4_ioremap_regs(pdev, 0); > + if (IS_ERR(dsi->regs)) > + return PTR_ERR(dsi->regs); > + > + if (DSI_PORT_READ(ID) != DSI_ID_VALUE) { > + dev_err(dev, "Port returned 0x%08x for ID instead of 0x%08x\n", > + DSI_PORT_READ(ID), DSI_ID_VALUE); > + return -ENODEV; > + } > + > + /* DSI1 has a broken AXI slave that doesn't respond to writes > + * from the ARM. It does handle writes from the DMA engine, > + * so set up a channel for talking to it. > + */ > + if (dsi->port == 1) { > + dsi->reg_dma_mem = dma_alloc_coherent(dev, 4, > + &dsi->reg_dma_paddr, > + GFP_KERNEL); > + if (!dsi->reg_dma_mem) { > + DRM_ERROR("Failed to get DMA memory\n"); > + return -ENOMEM; > + } > + > + dma_cap_zero(dma_mask); > + dma_cap_set(DMA_MEMCPY, dma_mask); > + dsi->reg_dma_chan = dma_request_chan_by_mask(&dma_mask); > + if (IS_ERR(dsi->reg_dma_chan)) { > + ret = PTR_ERR(dsi->reg_dma_chan); > + if (ret != -EPROBE_DEFER) > + DRM_ERROR("Failed to get DMA channel: %d\n", > + ret); > + return ret; > + } > + > + /* Get the physical address of the device's registers. The > + * struct resource for the regs gives us the bus address > + * instead. > + */ > + dsi->reg_paddr = be32_to_cpup(of_get_address(dev->of_node, > + 0, NULL, NULL)); > + } > + > + init_completion(&dsi->xfer_completion); > + /* At startup enable error-reporting interrupts and nothing else. */ > + DSI_PORT_WRITE(INT_EN, DSI1_INTERRUPTS_ALWAYS_ENABLED); > + /* Clear any existing interrupt state. */ > + DSI_PORT_WRITE(INT_STAT, DSI_PORT_READ(INT_STAT)); > + > + ret = devm_request_irq(dev, platform_get_irq(pdev, 0), > + vc4_dsi_irq_handler, 0, "vc4 dsi", dsi); > + if (ret) { > + if (ret != -EPROBE_DEFER) > + dev_err(dev, "Failed to get interrupt: %d\n", ret); > + return ret; > + } > + > + dsi->escape_clock = devm_clk_get(dev, "escape"); > + if (IS_ERR(dsi->escape_clock)) { > + ret = PTR_ERR(dsi->escape_clock); > + if (ret != -EPROBE_DEFER) > + dev_err(dev, "Failed to get escape clock: %d\n", ret); > + return ret; > + } > + > + dsi->pll_phy_clock = devm_clk_get(dev, "phy"); > + if (IS_ERR(dsi->pll_phy_clock)) { > + ret = PTR_ERR(dsi->pll_phy_clock); > + if (ret != -EPROBE_DEFER) > + dev_err(dev, "Failed to get phy clock: %d\n", ret); > + return ret; > + } > + > + dsi->pixel_clock = devm_clk_get(dev, "pixel"); > + if (IS_ERR(dsi->pixel_clock)) { > + ret = PTR_ERR(dsi->pixel_clock); > + if (ret != -EPROBE_DEFER) > + dev_err(dev, "Failed to get pixel clock: %d\n", ret); > + return ret; > + } > + > + /* The esc clock rate is supposed to always be 100Mhz. */ > + ret = clk_set_rate(dsi->escape_clock, 100 * 1000000); > + if (ret) { > + dev_err(dev, "Failed to set esc clock: %d\n", ret); > + return ret; > + } > + > + ret = vc4_dsi_init_phy_clocks(dsi); > + if (ret) > + return ret; > + > + if (dsi->port == 1) > + vc4->dsi1 = dsi; > + > + drm_encoder_init(drm, dsi->encoder, &vc4_dsi_encoder_funcs, > + DRM_MODE_ENCODER_DSI, NULL); > + drm_encoder_helper_add(dsi->encoder, &vc4_dsi_encoder_helper_funcs); > + > + dsi->connector = vc4_dsi_connector_init(drm, dsi); > + if (IS_ERR(dsi->connector)) { > + ret = PTR_ERR(dsi->connector); > + goto err_destroy_encoder; > + } > + > + dsi->dsi_host.ops = &vc4_dsi_host_ops; > + dsi->dsi_host.dev = dev; > + > + mipi_dsi_host_register(&dsi->dsi_host); > + > + dev_set_drvdata(dev, dsi); > + > + pm_runtime_enable(dev); > + > + return 0; > + > +err_destroy_encoder: > + vc4_dsi_encoder_destroy(dsi->encoder); > + > + return ret; > +} > + > +static void vc4_dsi_unbind(struct device *dev, struct device *master, > + void *data) > +{ > + struct drm_device *drm = dev_get_drvdata(master); > + struct vc4_dev *vc4 = to_vc4_dev(drm); > + struct vc4_dsi *dsi = dev_get_drvdata(dev); > + > + pm_runtime_disable(dev); > + > + vc4_dsi_connector_destroy(dsi->connector); > + vc4_dsi_encoder_destroy(dsi->encoder); > + > + mipi_dsi_host_unregister(&dsi->dsi_host); > + > + clk_disable_unprepare(dsi->pll_phy_clock); > + clk_disable_unprepare(dsi->escape_clock); > + > + if (dsi->port == 1) > + vc4->dsi1 = NULL; > +} > + > +static const struct component_ops vc4_dsi_ops = { > + .bind = vc4_dsi_bind, > + .unbind = vc4_dsi_unbind, > +}; > + > +static int vc4_dsi_dev_probe(struct platform_device *pdev) > +{ > + return component_add(&pdev->dev, &vc4_dsi_ops); > +} > + > +static int vc4_dsi_dev_remove(struct platform_device *pdev) > +{ > + component_del(&pdev->dev, &vc4_dsi_ops); > + return 0; > +} > + > +struct platform_driver vc4_dsi_driver = { > + .probe = vc4_dsi_dev_probe, > + .remove = vc4_dsi_dev_remove, > + .driver = { > + .name = "vc4_dsi", > + .of_match_table = vc4_dsi_dt_match, > + }, > +}; > -- > 2.11.0 > > _______________________________________________ > dri-devel mailing list > dri-devel@lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/dri-devel -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch From mboxrd@z Thu Jan 1 00:00:00 1970 From: daniel@ffwll.ch (Daniel Vetter) Date: Tue, 31 Jan 2017 20:51:59 +0100 Subject: [PATCH 07/11] drm/vc4: Add DSI driver In-Reply-To: <20161214194621.16499-8-eric@anholt.net> References: <20161214194621.16499-1-eric@anholt.net> <20161214194621.16499-8-eric@anholt.net> Message-ID: <20170131195159.kfqfmvtngxzvt63a@phenom.ffwll.local> To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org On Wed, Dec 14, 2016 at 11:46:17AM -0800, Eric Anholt wrote: > The DSI0 and DSI1 blocks on the 2835 are related hardware blocks. > Some registers move around, and the featureset is slightly different, > as DSI1 (the 4-lane DSI) is a later version of the hardware block. > This driver doesn't yet enable DSI0, since we don't have any hardware > to test against, but it does put a lot of the register definitions and > code in place. > > Signed-off-by: Eric Anholt Looks all neat, below a few semi-random ideas. Acked-by: Daniel Vetter > --- > drivers/gpu/drm/vc4/Kconfig | 2 + > drivers/gpu/drm/vc4/Makefile | 1 + > drivers/gpu/drm/vc4/vc4_debugfs.c | 1 + > drivers/gpu/drm/vc4/vc4_drv.c | 1 + > drivers/gpu/drm/vc4/vc4_drv.h | 5 + > drivers/gpu/drm/vc4/vc4_dsi.c | 1725 +++++++++++++++++++++++++++++++++++++ > 6 files changed, 1735 insertions(+) > create mode 100644 drivers/gpu/drm/vc4/vc4_dsi.c > > diff --git a/drivers/gpu/drm/vc4/Kconfig b/drivers/gpu/drm/vc4/Kconfig > index e53df59cb139..e1517d07cb7d 100644 > --- a/drivers/gpu/drm/vc4/Kconfig > +++ b/drivers/gpu/drm/vc4/Kconfig > @@ -2,10 +2,12 @@ config DRM_VC4 > tristate "Broadcom VC4 Graphics" > depends on ARCH_BCM2835 || COMPILE_TEST > depends on DRM > + depends on COMMON_CLK > select DRM_KMS_HELPER > select DRM_KMS_CMA_HELPER > select DRM_GEM_CMA_HELPER > select DRM_PANEL > + select DRM_MIPI_DSI > help > Choose this option if you have a system that has a Broadcom > VC4 GPU, such as the Raspberry Pi or other BCM2708/BCM2835. > diff --git a/drivers/gpu/drm/vc4/Makefile b/drivers/gpu/drm/vc4/Makefile > index 7757f69a8a77..61f45d122bd0 100644 > --- a/drivers/gpu/drm/vc4/Makefile > +++ b/drivers/gpu/drm/vc4/Makefile > @@ -8,6 +8,7 @@ vc4-y := \ > vc4_crtc.o \ > vc4_drv.o \ > vc4_dpi.o \ > + vc4_dsi.o \ > vc4_kms.o \ > vc4_gem.o \ > vc4_hdmi.o \ > diff --git a/drivers/gpu/drm/vc4/vc4_debugfs.c b/drivers/gpu/drm/vc4/vc4_debugfs.c > index caf817bac885..3ca476c6e057 100644 > --- a/drivers/gpu/drm/vc4/vc4_debugfs.c > +++ b/drivers/gpu/drm/vc4/vc4_debugfs.c > @@ -18,6 +18,7 @@ > static const struct drm_info_list vc4_debugfs_list[] = { > {"bo_stats", vc4_bo_stats_debugfs, 0}, > {"dpi_regs", vc4_dpi_debugfs_regs, 0}, > + {"dsi1_regs", vc4_dsi_debugfs_regs, 0, (void *)(uintptr_t)1}, > {"hdmi_regs", vc4_hdmi_debugfs_regs, 0}, > {"vec_regs", vc4_vec_debugfs_regs, 0}, > {"hvs_regs", vc4_hvs_debugfs_regs, 0}, > diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c > index bdab333979dc..2d2edc7dcf4a 100644 > --- a/drivers/gpu/drm/vc4/vc4_drv.c > +++ b/drivers/gpu/drm/vc4/vc4_drv.c > @@ -298,6 +298,7 @@ static struct platform_driver *const component_drivers[] = { > &vc4_hdmi_driver, > &vc4_vec_driver, > &vc4_dpi_driver, > + &vc4_dsi_driver, > &vc4_hvs_driver, > &vc4_crtc_driver, > &vc4_v3d_driver, > diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h > index b5c4bb14d0d1..723f0ec940ac 100644 > --- a/drivers/gpu/drm/vc4/vc4_drv.h > +++ b/drivers/gpu/drm/vc4/vc4_drv.h > @@ -17,6 +17,7 @@ struct vc4_dev { > struct vc4_crtc *crtc[3]; > struct vc4_v3d *v3d; > struct vc4_dpi *dpi; > + struct vc4_dsi *dsi1; > struct vc4_vec *vec; > > struct drm_fbdev_cma *fbdev; > @@ -465,6 +466,10 @@ void __iomem *vc4_ioremap_regs(struct platform_device *dev, int index); > extern struct platform_driver vc4_dpi_driver; > int vc4_dpi_debugfs_regs(struct seq_file *m, void *unused); > > +/* vc4_dsi.c */ > +extern struct platform_driver vc4_dsi_driver; > +int vc4_dsi_debugfs_regs(struct seq_file *m, void *unused); > + > /* vc4_gem.c */ > void vc4_gem_init(struct drm_device *dev); > void vc4_gem_destroy(struct drm_device *dev); > diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c > new file mode 100644 > index 000000000000..17fcac381dbb > --- /dev/null > +++ b/drivers/gpu/drm/vc4/vc4_dsi.c > @@ -0,0 +1,1725 @@ > +/* > + * Copyright (C) 2016 Broadcom > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License version 2 as published by > + * the Free Software Foundation. > + * > + * 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. > + * > + * You should have received a copy of the GNU General Public License along with > + * this program. If not, see . > + */ > + > +/** > + * DOC: VC4 DSI0/DSI1 module Since you're bothering with kerneldoc, I strongly recommend you add a vc4.rst in Documentation/gpu, include it together with the other drivers (atm only i915, but Noralf will add one for tinydrm) and then add stanzas to pull your kerneldoc in. That's the only way to lint it (at least for now, until maybe we merge Jani's make target to lint all the kerneldocs), and I think slowly building up driver docs would be really sweet. Anyway, just an idea for the future. > + * > + * BCM2835 contains two DSI modules, DSI0 and DSI1. DSI0 is a > + * single-lane DSI controller, while DSI1 is a more modern 4-lane DSI > + * controller. > + * > + * Most Raspberry Pi boards expose DSI1 as their "DISPLAY" connector, > + * while the compute module brings both DSI0 and DSI1 out. > + * > + * This driver has been tested for DSI1 video-mode display only > + * currently, with most of the information necessary for DSI0 > + * hopefully present. > + */ > + > +#include "drm_atomic_helper.h" > +#include "drm_crtc_helper.h" > +#include "drm_edid.h" > +#include "drm_mipi_dsi.h" > +#include "drm_panel.h" > +#include "linux/clk.h" > +#include "linux/clk-provider.h" > +#include "linux/completion.h" > +#include "linux/component.h" > +#include "linux/dmaengine.h" > +#include "linux/i2c.h" > +#include "linux/of_address.h" > +#include "linux/of_platform.h" > +#include "linux/pm_runtime.h" > +#include "vc4_drv.h" > +#include "vc4_regs.h" > + > +#define DSI_CMD_FIFO_DEPTH 16 > +#define DSI_PIX_FIFO_DEPTH 256 > +#define DSI_PIX_FIFO_WIDTH 4 > + > +#define DSI0_CTRL 0x00 > + > +/* Command packet control. */ > +#define DSI0_TXPKT1C 0x04 /* AKA PKTC */ > +#define DSI1_TXPKT1C 0x04 > +# define DSI_TXPKT1C_TRIG_CMD_MASK VC4_MASK(31, 24) > +# define DSI_TXPKT1C_TRIG_CMD_SHIFT 24 > +# define DSI_TXPKT1C_CMD_REPEAT_MASK VC4_MASK(23, 10) > +# define DSI_TXPKT1C_CMD_REPEAT_SHIFT 10 > + > +# define DSI_TXPKT1C_DISPLAY_NO_MASK VC4_MASK(9, 8) > +# define DSI_TXPKT1C_DISPLAY_NO_SHIFT 8 > +/* Short, trigger, BTA, or a long packet that fits all in CMDFIFO. */ > +# define DSI_TXPKT1C_DISPLAY_NO_SHORT 0 > +/* Primary display where cmdfifo provides part of the payload and > + * pixelvalve the rest. > + */ > +# define DSI_TXPKT1C_DISPLAY_NO_PRIMARY 1 > +/* Secondary display where cmdfifo provides part of the payload and > + * pixfifo the rest. > + */ > +# define DSI_TXPKT1C_DISPLAY_NO_SECONDARY 2 > + > +# define DSI_TXPKT1C_CMD_TX_TIME_MASK VC4_MASK(7, 6) > +# define DSI_TXPKT1C_CMD_TX_TIME_SHIFT 6 > + > +# define DSI_TXPKT1C_CMD_CTRL_MASK VC4_MASK(5, 4) > +# define DSI_TXPKT1C_CMD_CTRL_SHIFT 4 > +/* Command only. Uses TXPKT1H and DISPLAY_NO */ > +# define DSI_TXPKT1C_CMD_CTRL_TX 0 > +/* Command with BTA for either ack or read data. */ > +# define DSI_TXPKT1C_CMD_CTRL_RX 1 > +/* Trigger according to TRIG_CMD */ > +# define DSI_TXPKT1C_CMD_CTRL_TRIG 2 > +/* BTA alone for getting error status after a command, or a TE trigger > + * without a previous command. > + */ > +# define DSI_TXPKT1C_CMD_CTRL_BTA 3 > + > +# define DSI_TXPKT1C_CMD_MODE_LP BIT(3) > +# define DSI_TXPKT1C_CMD_TYPE_LONG BIT(2) > +# define DSI_TXPKT1C_CMD_TE_EN BIT(1) > +# define DSI_TXPKT1C_CMD_EN BIT(0) > + > +/* Command packet header. */ > +#define DSI0_TXPKT1H 0x08 /* AKA PKTH */ > +#define DSI1_TXPKT1H 0x08 > +# define DSI_TXPKT1H_BC_CMDFIFO_MASK VC4_MASK(31, 24) > +# define DSI_TXPKT1H_BC_CMDFIFO_SHIFT 24 > +# define DSI_TXPKT1H_BC_PARAM_MASK VC4_MASK(23, 8) > +# define DSI_TXPKT1H_BC_PARAM_SHIFT 8 > +# define DSI_TXPKT1H_BC_DT_MASK VC4_MASK(7, 0) > +# define DSI_TXPKT1H_BC_DT_SHIFT 0 > + > +#define DSI0_RXPKT1H 0x0c /* AKA RX1_PKTH */ > +#define DSI1_RXPKT1H 0x14 > +# define DSI_RXPKT1H_CRC_ERR BIT(31) > +# define DSI_RXPKT1H_DET_ERR BIT(30) > +# define DSI_RXPKT1H_ECC_ERR BIT(29) > +# define DSI_RXPKT1H_COR_ERR BIT(28) > +# define DSI_RXPKT1H_INCOMP_PKT BIT(25) > +# define DSI_RXPKT1H_PKT_TYPE_LONG BIT(24) > +/* Byte count if DSI_RXPKT1H_PKT_TYPE_LONG */ > +# define DSI_RXPKT1H_BC_PARAM_MASK VC4_MASK(23, 8) > +# define DSI_RXPKT1H_BC_PARAM_SHIFT 8 > +/* Short return bytes if !DSI_RXPKT1H_PKT_TYPE_LONG */ > +# define DSI_RXPKT1H_SHORT_1_MASK VC4_MASK(23, 16) > +# define DSI_RXPKT1H_SHORT_1_SHIFT 16 > +# define DSI_RXPKT1H_SHORT_0_MASK VC4_MASK(15, 8) > +# define DSI_RXPKT1H_SHORT_0_SHIFT 8 > +# define DSI_RXPKT1H_DT_LP_CMD_MASK VC4_MASK(7, 0) > +# define DSI_RXPKT1H_DT_LP_CMD_SHIFT 0 > + > +#define DSI0_RXPKT2H 0x10 /* AKA RX2_PKTH */ > +#define DSI1_RXPKT2H 0x18 > +# define DSI_RXPKT1H_DET_ERR BIT(30) > +# define DSI_RXPKT1H_ECC_ERR BIT(29) > +# define DSI_RXPKT1H_COR_ERR BIT(28) > +# define DSI_RXPKT1H_INCOMP_PKT BIT(25) > +# define DSI_RXPKT1H_BC_PARAM_MASK VC4_MASK(23, 8) > +# define DSI_RXPKT1H_BC_PARAM_SHIFT 8 > +# define DSI_RXPKT1H_DT_MASK VC4_MASK(7, 0) > +# define DSI_RXPKT1H_DT_SHIFT 0 > + > +#define DSI0_TXPKT_CMD_FIFO 0x14 /* AKA CMD_DATAF */ > +#define DSI1_TXPKT_CMD_FIFO 0x1c > + > +#define DSI0_DISP0_CTRL 0x18 > +# define DSI_DISP0_PIX_CLK_DIV_MASK VC4_MASK(21, 13) > +# define DSI_DISP0_PIX_CLK_DIV_SHIFT 13 > +# define DSI_DISP0_LP_STOP_CTRL_MASK VC4_MASK(12, 11) > +# define DSI_DISP0_LP_STOP_CTRL_SHIFT 11 > +# define DSI_DISP0_LP_STOP_DISABLE 0 > +# define DSI_DISP0_LP_STOP_PERLINE 1 > +# define DSI_DISP0_LP_STOP_PERFRAME 2 > + > +/* Transmit RGB pixels and null packets only during HACTIVE, instead > + * of going to LP-STOP. > + */ > +# define DSI_DISP_HACTIVE_NULL BIT(10) > +/* Transmit blanking packet only during vblank, instead of allowing LP-STOP. */ > +# define DSI_DISP_VBLP_CTRL BIT(9) > +/* Transmit blanking packet only during HFP, instead of allowing LP-STOP. */ > +# define DSI_DISP_HFP_CTRL BIT(8) > +/* Transmit blanking packet only during HBP, instead of allowing LP-STOP. */ > +# define DSI_DISP_HBP_CTRL BIT(7) > +# define DSI_DISP0_CHANNEL_MASK VC4_MASK(6, 5) > +# define DSI_DISP0_CHANNEL_SHIFT 5 > +/* Enables end events for HSYNC/VSYNC, not just start events. */ > +# define DSI_DISP0_ST_END BIT(4) > +# define DSI_DISP0_PFORMAT_MASK VC4_MASK(3, 2) > +# define DSI_DISP0_PFORMAT_SHIFT 2 > +# define DSI_PFORMAT_RGB565 0 > +# define DSI_PFORMAT_RGB666_PACKED 1 > +# define DSI_PFORMAT_RGB666 2 > +# define DSI_PFORMAT_RGB888 3 > +/* Default is VIDEO mode. */ > +# define DSI_DISP0_COMMAND_MODE BIT(1) > +# define DSI_DISP0_ENABLE BIT(0) > + > +#define DSI0_DISP1_CTRL 0x1c > +#define DSI1_DISP1_CTRL 0x2c > +/* Format of the data written to TXPKT_PIX_FIFO. */ > +# define DSI_DISP1_PFORMAT_MASK VC4_MASK(2, 1) > +# define DSI_DISP1_PFORMAT_SHIFT 1 > +# define DSI_DISP1_PFORMAT_16BIT 0 > +# define DSI_DISP1_PFORMAT_24BIT 1 > +# define DSI_DISP1_PFORMAT_32BIT_LE 2 > +# define DSI_DISP1_PFORMAT_32BIT_BE 3 > + > +/* DISP1 is always command mode. */ > +# define DSI_DISP1_ENABLE BIT(0) > + > +#define DSI0_TXPKT_PIX_FIFO 0x20 /* AKA PIX_FIFO */ > + > +#define DSI0_INT_STAT 0x24 > +#define DSI0_INT_EN 0x28 > +# define DSI1_INT_PHY_D3_ULPS BIT(30) > +# define DSI1_INT_PHY_D3_STOP BIT(29) > +# define DSI1_INT_PHY_D2_ULPS BIT(28) > +# define DSI1_INT_PHY_D2_STOP BIT(27) > +# define DSI1_INT_PHY_D1_ULPS BIT(26) > +# define DSI1_INT_PHY_D1_STOP BIT(25) > +# define DSI1_INT_PHY_D0_ULPS BIT(24) > +# define DSI1_INT_PHY_D0_STOP BIT(23) > +# define DSI1_INT_FIFO_ERR BIT(22) > +# define DSI1_INT_PHY_DIR_RTF BIT(21) > +# define DSI1_INT_PHY_RXLPDT BIT(20) > +# define DSI1_INT_PHY_RXTRIG BIT(19) > +# define DSI1_INT_PHY_D0_LPDT BIT(18) > +# define DSI1_INT_PHY_DIR_FTR BIT(17) > + > +/* Signaled when the clock lane enters the given state. */ > +# define DSI1_INT_PHY_CLOCK_ULPS BIT(16) > +# define DSI1_INT_PHY_CLOCK_HS BIT(15) > +# define DSI1_INT_PHY_CLOCK_STOP BIT(14) > + > +/* Signaled on timeouts */ > +# define DSI1_INT_PR_TO BIT(13) > +# define DSI1_INT_TA_TO BIT(12) > +# define DSI1_INT_LPRX_TO BIT(11) > +# define DSI1_INT_HSTX_TO BIT(10) > + > +/* Contention on a line when trying to drive the line low */ > +# define DSI1_INT_ERR_CONT_LP1 BIT(9) > +# define DSI1_INT_ERR_CONT_LP0 BIT(8) > + > +/* Control error: incorrect line state sequence on data lane 0. */ > +# define DSI1_INT_ERR_CONTROL BIT(7) > +/* LPDT synchronization error (bits received not a multiple of 8. */ > + > +# define DSI1_INT_ERR_SYNC_ESC BIT(6) > +/* Signaled after receiving an error packet from the display in > + * response to a read. > + */ > +# define DSI1_INT_RXPKT2 BIT(5) > +/* Signaled after receiving a packet. The header and optional short > + * response will be in RXPKT1H, and a long response will be in the > + * RXPKT_FIFO. > + */ > +# define DSI1_INT_RXPKT1 BIT(4) > +# define DSI1_INT_TXPKT2_DONE BIT(3) > +# define DSI1_INT_TXPKT2_END BIT(2) > +/* Signaled after all repeats of TXPKT1 are transferred. */ > +# define DSI1_INT_TXPKT1_DONE BIT(1) > +/* Signaled after each TXPKT1 repeat is scheduled. */ > +# define DSI1_INT_TXPKT1_END BIT(0) > + > +#define DSI1_INTERRUPTS_ALWAYS_ENABLED (DSI1_INT_ERR_SYNC_ESC | \ > + DSI1_INT_ERR_CONTROL | \ > + DSI1_INT_ERR_CONT_LP0 | \ > + DSI1_INT_ERR_CONT_LP1 | \ > + DSI1_INT_HSTX_TO | \ > + DSI1_INT_LPRX_TO | \ > + DSI1_INT_TA_TO | \ > + DSI1_INT_PR_TO) > + > +#define DSI0_STAT 0x2c > +#define DSI0_HSTX_TO_CNT 0x30 > +#define DSI0_LPRX_TO_CNT 0x34 > +#define DSI0_TA_TO_CNT 0x38 > +#define DSI0_PR_TO_CNT 0x3c > +#define DSI0_PHYC 0x40 > +# define DSI1_PHYC_ESC_CLK_LPDT_MASK VC4_MASK(25, 20) > +# define DSI1_PHYC_ESC_CLK_LPDT_SHIFT 20 > +# define DSI1_PHYC_HS_CLK_CONTINUOUS BIT(18) > +# define DSI0_PHYC_ESC_CLK_LPDT_MASK VC4_MASK(17, 12) > +# define DSI0_PHYC_ESC_CLK_LPDT_SHIFT 12 > +# define DSI1_PHYC_CLANE_ULPS BIT(17) > +# define DSI1_PHYC_CLANE_ENABLE BIT(16) > +# define DSI_PHYC_DLANE3_ULPS BIT(13) > +# define DSI_PHYC_DLANE3_ENABLE BIT(12) > +# define DSI0_PHYC_HS_CLK_CONTINUOUS BIT(10) > +# define DSI0_PHYC_CLANE_ULPS BIT(9) > +# define DSI_PHYC_DLANE2_ULPS BIT(9) > +# define DSI0_PHYC_CLANE_ENABLE BIT(8) > +# define DSI_PHYC_DLANE2_ENABLE BIT(8) > +# define DSI_PHYC_DLANE1_ULPS BIT(5) > +# define DSI_PHYC_DLANE1_ENABLE BIT(4) > +# define DSI_PHYC_DLANE0_FORCE_STOP BIT(2) > +# define DSI_PHYC_DLANE0_ULPS BIT(1) > +# define DSI_PHYC_DLANE0_ENABLE BIT(0) > + > +#define DSI0_HS_CLT0 0x44 > +#define DSI0_HS_CLT1 0x48 > +#define DSI0_HS_CLT2 0x4c > +#define DSI0_HS_DLT3 0x50 > +#define DSI0_HS_DLT4 0x54 > +#define DSI0_HS_DLT5 0x58 > +#define DSI0_HS_DLT6 0x5c > +#define DSI0_HS_DLT7 0x60 > + > +#define DSI0_PHY_AFEC0 0x64 > +# define DSI0_PHY_AFEC0_DDR2CLK_EN BIT(26) > +# define DSI0_PHY_AFEC0_DDRCLK_EN BIT(25) > +# define DSI0_PHY_AFEC0_LATCH_ULPS BIT(24) > +# define DSI1_PHY_AFEC0_IDR_DLANE3_MASK VC4_MASK(31, 29) > +# define DSI1_PHY_AFEC0_IDR_DLANE3_SHIFT 29 > +# define DSI1_PHY_AFEC0_IDR_DLANE2_MASK VC4_MASK(28, 26) > +# define DSI1_PHY_AFEC0_IDR_DLANE2_SHIFT 26 > +# define DSI1_PHY_AFEC0_IDR_DLANE1_MASK VC4_MASK(27, 23) > +# define DSI1_PHY_AFEC0_IDR_DLANE1_SHIFT 23 > +# define DSI1_PHY_AFEC0_IDR_DLANE0_MASK VC4_MASK(22, 20) > +# define DSI1_PHY_AFEC0_IDR_DLANE0_SHIFT 20 > +# define DSI1_PHY_AFEC0_IDR_CLANE_MASK VC4_MASK(19, 17) > +# define DSI1_PHY_AFEC0_IDR_CLANE_SHIFT 17 > +# define DSI0_PHY_AFEC0_ACTRL_DLANE1_MASK VC4_MASK(23, 20) > +# define DSI0_PHY_AFEC0_ACTRL_DLANE1_SHIFT 20 > +# define DSI0_PHY_AFEC0_ACTRL_DLANE0_MASK VC4_MASK(19, 16) > +# define DSI0_PHY_AFEC0_ACTRL_DLANE0_SHIFT 16 > +# define DSI0_PHY_AFEC0_ACTRL_CLANE_MASK VC4_MASK(15, 12) > +# define DSI0_PHY_AFEC0_ACTRL_CLANE_SHIFT 12 > +# define DSI1_PHY_AFEC0_DDR2CLK_EN BIT(16) > +# define DSI1_PHY_AFEC0_DDRCLK_EN BIT(15) > +# define DSI1_PHY_AFEC0_LATCH_ULPS BIT(14) > +# define DSI1_PHY_AFEC0_RESET BIT(13) > +# define DSI1_PHY_AFEC0_PD BIT(12) > +# define DSI0_PHY_AFEC0_RESET BIT(11) > +# define DSI1_PHY_AFEC0_PD_BG BIT(11) > +# define DSI0_PHY_AFEC0_PD BIT(10) > +# define DSI1_PHY_AFEC0_PD_DLANE3 BIT(10) > +# define DSI0_PHY_AFEC0_PD_BG BIT(9) > +# define DSI1_PHY_AFEC0_PD_DLANE2 BIT(9) > +# define DSI0_PHY_AFEC0_PD_DLANE1 BIT(8) > +# define DSI1_PHY_AFEC0_PD_DLANE1 BIT(8) > +# define DSI_PHY_AFEC0_PTATADJ_MASK VC4_MASK(7, 4) > +# define DSI_PHY_AFEC0_PTATADJ_SHIFT 4 > +# define DSI_PHY_AFEC0_CTATADJ_MASK VC4_MASK(3, 0) > +# define DSI_PHY_AFEC0_CTATADJ_SHIFT 0 > + > +#define DSI0_PHY_AFEC1 0x68 > +# define DSI0_PHY_AFEC1_IDR_DLANE1_MASK VC4_MASK(10, 8) > +# define DSI0_PHY_AFEC1_IDR_DLANE1_SHIFT 8 > +# define DSI0_PHY_AFEC1_IDR_DLANE0_MASK VC4_MASK(6, 4) > +# define DSI0_PHY_AFEC1_IDR_DLANE0_SHIFT 4 > +# define DSI0_PHY_AFEC1_IDR_CLANE_MASK VC4_MASK(2, 0) > +# define DSI0_PHY_AFEC1_IDR_CLANE_SHIFT 0 > + > +#define DSI0_TST_SEL 0x6c > +#define DSI0_TST_MON 0x70 > +#define DSI0_ID 0x74 > +# define DSI_ID_VALUE 0x00647369 > + > +#define DSI1_CTRL 0x00 > +# define DSI_CTRL_HS_CLKC_MASK VC4_MASK(15, 14) > +# define DSI_CTRL_HS_CLKC_SHIFT 14 > +# define DSI_CTRL_HS_CLKC_BYTE 0 > +# define DSI_CTRL_HS_CLKC_DDR2 1 > +# define DSI_CTRL_HS_CLKC_DDR 2 > + > +# define DSI_CTRL_RX_LPDT_EOT_DISABLE BIT(13) > +# define DSI_CTRL_LPDT_EOT_DISABLE BIT(12) > +# define DSI_CTRL_HSDT_EOT_DISABLE BIT(11) > +# define DSI_CTRL_SOFT_RESET_CFG BIT(10) > +# define DSI_CTRL_CAL_BYTE BIT(9) > +# define DSI_CTRL_INV_BYTE BIT(8) > +# define DSI_CTRL_CLR_LDF BIT(7) > +# define DSI0_CTRL_CLR_PBCF BIT(6) > +# define DSI1_CTRL_CLR_RXF BIT(6) > +# define DSI0_CTRL_CLR_CPBCF BIT(5) > +# define DSI1_CTRL_CLR_PDF BIT(5) > +# define DSI0_CTRL_CLR_PDF BIT(4) > +# define DSI1_CTRL_CLR_CDF BIT(4) > +# define DSI0_CTRL_CLR_CDF BIT(3) > +# define DSI0_CTRL_CTRL2 BIT(2) > +# define DSI1_CTRL_DISABLE_DISP_CRCC BIT(2) > +# define DSI0_CTRL_CTRL1 BIT(1) > +# define DSI1_CTRL_DISABLE_DISP_ECCC BIT(1) > +# define DSI0_CTRL_CTRL0 BIT(0) > +# define DSI1_CTRL_EN BIT(0) > +# define DSI0_CTRL_RESET_FIFOS (DSI_CTRL_CLR_LDF | \ > + DSI0_CTRL_CLR_PBCF | \ > + DSI0_CTRL_CLR_CPBCF | \ > + DSI0_CTRL_CLR_PDF | \ > + DSI0_CTRL_CLR_CDF) > +# define DSI1_CTRL_RESET_FIFOS (DSI_CTRL_CLR_LDF | \ > + DSI1_CTRL_CLR_RXF | \ > + DSI1_CTRL_CLR_PDF | \ > + DSI1_CTRL_CLR_CDF) > + > +#define DSI1_TXPKT2C 0x0c > +#define DSI1_TXPKT2H 0x10 > +#define DSI1_TXPKT_PIX_FIFO 0x20 > +#define DSI1_RXPKT_FIFO 0x24 > +#define DSI1_DISP0_CTRL 0x28 > +#define DSI1_INT_STAT 0x30 > +#define DSI1_INT_EN 0x34 > +/* State reporting bits. These mostly behave like INT_STAT, where > + * writing a 1 clears the bit. > + */ > +#define DSI1_STAT 0x38 > +# define DSI1_STAT_PHY_D3_ULPS BIT(31) > +# define DSI1_STAT_PHY_D3_STOP BIT(30) > +# define DSI1_STAT_PHY_D2_ULPS BIT(29) > +# define DSI1_STAT_PHY_D2_STOP BIT(28) > +# define DSI1_STAT_PHY_D1_ULPS BIT(27) > +# define DSI1_STAT_PHY_D1_STOP BIT(26) > +# define DSI1_STAT_PHY_D0_ULPS BIT(25) > +# define DSI1_STAT_PHY_D0_STOP BIT(24) > +# define DSI1_STAT_FIFO_ERR BIT(23) > +# define DSI1_STAT_PHY_RXLPDT BIT(22) > +# define DSI1_STAT_PHY_RXTRIG BIT(21) > +# define DSI1_STAT_PHY_D0_LPDT BIT(20) > +/* Set when in forward direction */ > +# define DSI1_STAT_PHY_DIR BIT(19) > +# define DSI1_STAT_PHY_CLOCK_ULPS BIT(18) > +# define DSI1_STAT_PHY_CLOCK_HS BIT(17) > +# define DSI1_STAT_PHY_CLOCK_STOP BIT(16) > +# define DSI1_STAT_PR_TO BIT(15) > +# define DSI1_STAT_TA_TO BIT(14) > +# define DSI1_STAT_LPRX_TO BIT(13) > +# define DSI1_STAT_HSTX_TO BIT(12) > +# define DSI1_STAT_ERR_CONT_LP1 BIT(11) > +# define DSI1_STAT_ERR_CONT_LP0 BIT(10) > +# define DSI1_STAT_ERR_CONTROL BIT(9) > +# define DSI1_STAT_ERR_SYNC_ESC BIT(8) > +# define DSI1_STAT_RXPKT2 BIT(7) > +# define DSI1_STAT_RXPKT1 BIT(6) > +# define DSI1_STAT_TXPKT2_BUSY BIT(5) > +# define DSI1_STAT_TXPKT2_DONE BIT(4) > +# define DSI1_STAT_TXPKT2_END BIT(3) > +# define DSI1_STAT_TXPKT1_BUSY BIT(2) > +# define DSI1_STAT_TXPKT1_DONE BIT(1) > +# define DSI1_STAT_TXPKT1_END BIT(0) > + > +#define DSI1_HSTX_TO_CNT 0x3c > +#define DSI1_LPRX_TO_CNT 0x40 > +#define DSI1_TA_TO_CNT 0x44 > +#define DSI1_PR_TO_CNT 0x48 > +#define DSI1_PHYC 0x4c > + > +#define DSI1_HS_CLT0 0x50 > +# define DSI_HS_CLT0_CZERO_MASK VC4_MASK(26, 18) > +# define DSI_HS_CLT0_CZERO_SHIFT 18 > +# define DSI_HS_CLT0_CPRE_MASK VC4_MASK(17, 9) > +# define DSI_HS_CLT0_CPRE_SHIFT 9 > +# define DSI_HS_CLT0_CPREP_MASK VC4_MASK(8, 0) > +# define DSI_HS_CLT0_CPREP_SHIFT 0 > + > +#define DSI1_HS_CLT1 0x54 > +# define DSI_HS_CLT1_CTRAIL_MASK VC4_MASK(17, 9) > +# define DSI_HS_CLT1_CTRAIL_SHIFT 9 > +# define DSI_HS_CLT1_CPOST_MASK VC4_MASK(8, 0) > +# define DSI_HS_CLT1_CPOST_SHIFT 0 > + > +#define DSI1_HS_CLT2 0x58 > +# define DSI_HS_CLT2_WUP_MASK VC4_MASK(23, 0) > +# define DSI_HS_CLT2_WUP_SHIFT 0 > + > +#define DSI1_HS_DLT3 0x5c > +# define DSI_HS_DLT3_EXIT_MASK VC4_MASK(26, 18) > +# define DSI_HS_DLT3_EXIT_SHIFT 18 > +# define DSI_HS_DLT3_ZERO_MASK VC4_MASK(17, 9) > +# define DSI_HS_DLT3_ZERO_SHIFT 9 > +# define DSI_HS_DLT3_PRE_MASK VC4_MASK(8, 0) > +# define DSI_HS_DLT3_PRE_SHIFT 0 > + > +#define DSI1_HS_DLT4 0x60 > +# define DSI_HS_DLT4_ANLAT_MASK VC4_MASK(22, 18) > +# define DSI_HS_DLT4_ANLAT_SHIFT 18 > +# define DSI_HS_DLT4_TRAIL_MASK VC4_MASK(17, 9) > +# define DSI_HS_DLT4_TRAIL_SHIFT 9 > +# define DSI_HS_DLT4_LPX_MASK VC4_MASK(8, 0) > +# define DSI_HS_DLT4_LPX_SHIFT 0 > + > +#define DSI1_HS_DLT5 0x64 > +# define DSI_HS_DLT5_INIT_MASK VC4_MASK(23, 0) > +# define DSI_HS_DLT5_INIT_SHIFT 0 > + > +#define DSI1_HS_DLT6 0x68 > +# define DSI_HS_DLT6_TA_GET_MASK VC4_MASK(31, 24) > +# define DSI_HS_DLT6_TA_GET_SHIFT 24 > +# define DSI_HS_DLT6_TA_SURE_MASK VC4_MASK(23, 16) > +# define DSI_HS_DLT6_TA_SURE_SHIFT 16 > +# define DSI_HS_DLT6_TA_GO_MASK VC4_MASK(15, 8) > +# define DSI_HS_DLT6_TA_GO_SHIFT 8 > +# define DSI_HS_DLT6_LP_LPX_MASK VC4_MASK(7, 0) > +# define DSI_HS_DLT6_LP_LPX_SHIFT 0 > + > +#define DSI1_HS_DLT7 0x6c > +# define DSI_HS_DLT7_LP_WUP_MASK VC4_MASK(23, 0) > +# define DSI_HS_DLT7_LP_WUP_SHIFT 0 > + > +#define DSI1_PHY_AFEC0 0x70 > + > +#define DSI1_PHY_AFEC1 0x74 > +# define DSI1_PHY_AFEC1_ACTRL_DLANE3_MASK VC4_MASK(19, 16) > +# define DSI1_PHY_AFEC1_ACTRL_DLANE3_SHIFT 16 > +# define DSI1_PHY_AFEC1_ACTRL_DLANE2_MASK VC4_MASK(15, 12) > +# define DSI1_PHY_AFEC1_ACTRL_DLANE2_SHIFT 12 > +# define DSI1_PHY_AFEC1_ACTRL_DLANE1_MASK VC4_MASK(11, 8) > +# define DSI1_PHY_AFEC1_ACTRL_DLANE1_SHIFT 8 > +# define DSI1_PHY_AFEC1_ACTRL_DLANE0_MASK VC4_MASK(7, 4) > +# define DSI1_PHY_AFEC1_ACTRL_DLANE0_SHIFT 4 > +# define DSI1_PHY_AFEC1_ACTRL_CLANE_MASK VC4_MASK(3, 0) > +# define DSI1_PHY_AFEC1_ACTRL_CLANE_SHIFT 0 > + > +#define DSI1_TST_SEL 0x78 > +#define DSI1_TST_MON 0x7c > +#define DSI1_PHY_TST1 0x80 > +#define DSI1_PHY_TST2 0x84 > +#define DSI1_PHY_FIFO_STAT 0x88 > +/* Actually, all registers in the range that aren't otherwise claimed > + * will return the ID. > + */ > +#define DSI1_ID 0x8c > + > +/* General DSI hardware state. */ > +struct vc4_dsi { > + struct platform_device *pdev; > + > + struct mipi_dsi_host dsi_host; > + struct drm_encoder *encoder; > + struct drm_connector *connector; > + struct drm_panel *panel; > + > + void __iomem *regs; > + > + struct dma_chan *reg_dma_chan; > + dma_addr_t reg_dma_paddr; > + u32 *reg_dma_mem; > + dma_addr_t reg_paddr; > + > + /* Whether we're on bcm2835's DSI0 or DSI1. */ > + int port; > + > + /* DSI channel for the panel we're connected to. */ > + u32 channel; > + u32 lanes; > + enum mipi_dsi_pixel_format format; > + u32 mode_flags; > + > + /* Input clock from CPRMAN to the digital PHY, for the DSI > + * escape clock. > + */ > + struct clk *escape_clock; > + > + /* Input clock to the analog PHY, used to generate the DSI bit > + * clock. > + */ > + struct clk *pll_phy_clock; > + > + /* HS Clocks generated within the DSI analog PHY. */ > + struct clk_fixed_factor phy_clocks[3]; > + > + struct clk_onecell_data clk_onecell; > + > + /* Pixel clock output to the pixelvalve, generated from the HS > + * clock. > + */ > + struct clk *pixel_clock; > + > + struct completion xfer_completion; > + int xfer_result; > +}; > + > +#define host_to_dsi(host) container_of(host, struct vc4_dsi, dsi_host) > + > +static inline void > +dsi_dma_workaround_write(struct vc4_dsi *dsi, u32 offset, u32 val) > +{ > + struct dma_chan *chan = dsi->reg_dma_chan; > + struct dma_async_tx_descriptor *tx; > + dma_cookie_t cookie; > + int ret; > + > + /* DSI0 should be able to write normally. */ > + if (!chan) { > + writel(val, dsi->regs + offset); > + return; > + } > + > + *dsi->reg_dma_mem = val; > + > + tx = chan->device->device_prep_dma_memcpy(chan, > + dsi->reg_paddr + offset, > + dsi->reg_dma_paddr, > + 4, 0); > + if (!tx) { > + DRM_ERROR("Failed to set up DMA register write\n"); > + return; > + } > + > + cookie = tx->tx_submit(tx); > + ret = dma_submit_error(cookie); > + if (ret) { > + DRM_ERROR("Failed to submit DMA: %d\n", ret); > + return; > + } > + ret = dma_sync_wait(chan, cookie); > + if (ret) > + DRM_ERROR("Failed to wait for DMA: %d\n", ret); > +} > + > +#define DSI_READ(offset) readl(dsi->regs + (offset)) > +#define DSI_WRITE(offset, val) dsi_dma_workaround_write(dsi, offset, val) > +#define DSI_PORT_READ(offset) \ > + DSI_READ(dsi->port ? DSI1_##offset : DSI0_##offset) > +#define DSI_PORT_WRITE(offset, val) \ > + DSI_WRITE(dsi->port ? DSI1_##offset : DSI0_##offset, val) > +#define DSI_PORT_BIT(bit) (dsi->port ? DSI1_##bit : DSI0_##bit) > + > +/* VC4 DSI encoder KMS struct */ > +struct vc4_dsi_encoder { > + struct vc4_encoder base; > + struct vc4_dsi *dsi; > +}; > + > +static inline struct vc4_dsi_encoder * > +to_vc4_dsi_encoder(struct drm_encoder *encoder) > +{ > + return container_of(encoder, struct vc4_dsi_encoder, base.base); > +} > + > +/* VC4 DSI connector KMS struct */ > +struct vc4_dsi_connector { > + struct drm_connector base; > + struct vc4_dsi *dsi; > +}; > + > +static inline struct vc4_dsi_connector * > +to_vc4_dsi_connector(struct drm_connector *connector) > +{ > + return container_of(connector, struct vc4_dsi_connector, base); > +} > + > +#define DSI_REG(reg) { reg, #reg } > +static const struct { > + u32 reg; > + const char *name; > +} dsi0_regs[] = { > + DSI_REG(DSI0_CTRL), > + DSI_REG(DSI0_STAT), > + DSI_REG(DSI0_HSTX_TO_CNT), > + DSI_REG(DSI0_LPRX_TO_CNT), > + DSI_REG(DSI0_TA_TO_CNT), > + DSI_REG(DSI0_PR_TO_CNT), > + DSI_REG(DSI0_DISP0_CTRL), > + DSI_REG(DSI0_DISP1_CTRL), > + DSI_REG(DSI0_INT_STAT), > + DSI_REG(DSI0_INT_EN), > + DSI_REG(DSI0_PHYC), > + DSI_REG(DSI0_HS_CLT0), > + DSI_REG(DSI0_HS_CLT1), > + DSI_REG(DSI0_HS_CLT2), > + DSI_REG(DSI0_HS_DLT3), > + DSI_REG(DSI0_HS_DLT4), > + DSI_REG(DSI0_HS_DLT5), > + DSI_REG(DSI0_HS_DLT6), > + DSI_REG(DSI0_HS_DLT7), > + DSI_REG(DSI0_PHY_AFEC0), > + DSI_REG(DSI0_PHY_AFEC1), > + DSI_REG(DSI0_ID), > +}; > + > +static const struct { > + u32 reg; > + const char *name; > +} dsi1_regs[] = { > + DSI_REG(DSI1_CTRL), > + DSI_REG(DSI1_STAT), > + DSI_REG(DSI1_HSTX_TO_CNT), > + DSI_REG(DSI1_LPRX_TO_CNT), > + DSI_REG(DSI1_TA_TO_CNT), > + DSI_REG(DSI1_PR_TO_CNT), > + DSI_REG(DSI1_DISP0_CTRL), > + DSI_REG(DSI1_DISP1_CTRL), > + DSI_REG(DSI1_INT_STAT), > + DSI_REG(DSI1_INT_EN), > + DSI_REG(DSI1_PHYC), > + DSI_REG(DSI1_HS_CLT0), > + DSI_REG(DSI1_HS_CLT1), > + DSI_REG(DSI1_HS_CLT2), > + DSI_REG(DSI1_HS_DLT3), > + DSI_REG(DSI1_HS_DLT4), > + DSI_REG(DSI1_HS_DLT5), > + DSI_REG(DSI1_HS_DLT6), > + DSI_REG(DSI1_HS_DLT7), > + DSI_REG(DSI1_PHY_AFEC0), > + DSI_REG(DSI1_PHY_AFEC1), > + DSI_REG(DSI1_ID), > +}; > + > +static void vc4_dsi_dump_regs(struct vc4_dsi *dsi) > +{ > + int i; > + > + if (dsi->port == 0) { > + for (i = 0; i < ARRAY_SIZE(dsi0_regs); i++) { > + DRM_INFO("0x%04x (%s): 0x%08x\n", > + dsi0_regs[i].reg, dsi0_regs[i].name, > + DSI_READ(dsi0_regs[i].reg)); > + } > + } else { > + for (i = 0; i < ARRAY_SIZE(dsi1_regs); i++) { > + DRM_INFO("0x%04x (%s): 0x%08x\n", > + dsi1_regs[i].reg, dsi1_regs[i].name, > + DSI_READ(dsi1_regs[i].reg)); > + } > + } > +} > + > +#ifdef CONFIG_DEBUG_FS > +int vc4_dsi_debugfs_regs(struct seq_file *m, void *unused) > +{ > + struct drm_info_node *node = (struct drm_info_node *)m->private; > + struct drm_device *drm = node->minor->dev; > + struct vc4_dev *vc4 = to_vc4_dev(drm); > + int dsi_index = (uintptr_t)node->info_ent->data; > + struct vc4_dsi *dsi = (dsi_index == 1 ? vc4->dsi1 : NULL); > + int i; > + > + if (!dsi) > + return 0; > + > + if (dsi->port == 0) { > + for (i = 0; i < ARRAY_SIZE(dsi0_regs); i++) { > + seq_printf(m, "0x%04x (%s): 0x%08x\n", > + dsi0_regs[i].reg, dsi0_regs[i].name, > + DSI_READ(dsi0_regs[i].reg)); > + } > + } else { > + for (i = 0; i < ARRAY_SIZE(dsi1_regs); i++) { > + seq_printf(m, "0x%04x (%s): 0x%08x\n", > + dsi1_regs[i].reg, dsi1_regs[i].name, > + DSI_READ(dsi1_regs[i].reg)); > + } > + } > + > + return 0; > +} > +#endif > + > +static enum drm_connector_status > +vc4_dsi_connector_detect(struct drm_connector *connector, bool force) > +{ > + struct vc4_dsi_connector *vc4_connector = > + to_vc4_dsi_connector(connector); > + struct vc4_dsi *dsi = vc4_connector->dsi; > + > + if (dsi->panel) > + return connector_status_connected; > + else > + return connector_status_disconnected; > +} > + > +static void vc4_dsi_connector_destroy(struct drm_connector *connector) > +{ > + drm_connector_unregister(connector); > + drm_connector_cleanup(connector); > +} > + > +static int vc4_dsi_connector_get_modes(struct drm_connector *connector) > +{ > + struct vc4_dsi_connector *vc4_connector = > + to_vc4_dsi_connector(connector); > + struct vc4_dsi *dsi = vc4_connector->dsi; > + > + if (dsi->panel) > + return drm_panel_get_modes(dsi->panel); > + > + return 0; > +} I'm still hoping that somewhen someone adds a drm_panel * pointer to drm_connector and writes the glue functions in a helper library so we could garbage-collect all our copies of the same stuff implementing ->detect and ->get_modes ... > + > +static const struct drm_connector_funcs vc4_dsi_connector_funcs = { > + .dpms = drm_atomic_helper_connector_dpms, > + .detect = vc4_dsi_connector_detect, > + .fill_modes = drm_helper_probe_single_connector_modes, > + .destroy = vc4_dsi_connector_destroy, > + .reset = drm_atomic_helper_connector_reset, > + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, > + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, > +}; > + > +static const struct drm_connector_helper_funcs vc4_dsi_connector_helper_funcs = { > + .get_modes = vc4_dsi_connector_get_modes, > +}; > + > +static struct drm_connector *vc4_dsi_connector_init(struct drm_device *dev, > + struct vc4_dsi *dsi) > +{ > + struct drm_connector *connector = NULL; > + struct vc4_dsi_connector *dsi_connector; > + int ret = 0; > + > + dsi_connector = devm_kzalloc(dev->dev, sizeof(*dsi_connector), > + GFP_KERNEL); > + if (!dsi_connector) { > + ret = -ENOMEM; > + goto fail; > + } > + connector = &dsi_connector->base; > + > + dsi_connector->dsi = dsi; > + > + drm_connector_init(dev, connector, &vc4_dsi_connector_funcs, > + DRM_MODE_CONNECTOR_DSI); > + drm_connector_helper_add(connector, &vc4_dsi_connector_helper_funcs); > + > + connector->polled = 0; > + connector->interlace_allowed = 0; > + connector->doublescan_allowed = 0; > + > + drm_mode_connector_attach_encoder(connector, dsi->encoder); > + > + return connector; > + > +fail: > + if (connector) > + vc4_dsi_connector_destroy(connector); > + > + return ERR_PTR(ret); > +} > + > +static void vc4_dsi_encoder_destroy(struct drm_encoder *encoder) > +{ > + drm_encoder_cleanup(encoder); > +} > + > +static const struct drm_encoder_funcs vc4_dsi_encoder_funcs = { > + .destroy = vc4_dsi_encoder_destroy, > +}; > + > +static void vc4_dsi_latch_ulps(struct vc4_dsi *dsi, bool latch) > +{ > + u32 afec0 = DSI_PORT_READ(PHY_AFEC0); > + > + if (latch) > + afec0 |= DSI_PORT_BIT(PHY_AFEC0_LATCH_ULPS); > + else > + afec0 &= ~DSI_PORT_BIT(PHY_AFEC0_LATCH_ULPS); > + > + DSI_PORT_WRITE(PHY_AFEC0, afec0); > +} > + > +/* Enters or exits Ultra Low Power State. */ > +static void vc4_dsi_ulps(struct vc4_dsi *dsi, bool ulps) > +{ > + bool continuous = dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS; > + u32 phyc_ulps = ((continuous ? DSI_PORT_BIT(PHYC_CLANE_ULPS) : 0) | > + DSI_PHYC_DLANE0_ULPS | > + (dsi->lanes > 1 ? DSI_PHYC_DLANE1_ULPS : 0) | > + (dsi->lanes > 2 ? DSI_PHYC_DLANE2_ULPS : 0) | > + (dsi->lanes > 3 ? DSI_PHYC_DLANE3_ULPS : 0)); > + u32 stat_ulps = ((continuous ? DSI1_STAT_PHY_CLOCK_ULPS : 0) | > + DSI1_STAT_PHY_D0_ULPS | > + (dsi->lanes > 1 ? DSI1_STAT_PHY_D1_ULPS : 0) | > + (dsi->lanes > 2 ? DSI1_STAT_PHY_D2_ULPS : 0) | > + (dsi->lanes > 3 ? DSI1_STAT_PHY_D3_ULPS : 0)); > + u32 stat_stop = ((continuous ? DSI1_STAT_PHY_CLOCK_STOP : 0) | > + DSI1_STAT_PHY_D0_STOP | > + (dsi->lanes > 1 ? DSI1_STAT_PHY_D1_STOP : 0) | > + (dsi->lanes > 2 ? DSI1_STAT_PHY_D2_STOP : 0) | > + (dsi->lanes > 3 ? DSI1_STAT_PHY_D3_STOP : 0)); > + int ret; > + > + DSI_PORT_WRITE(STAT, stat_ulps); > + DSI_PORT_WRITE(PHYC, DSI_PORT_READ(PHYC) | phyc_ulps); > + ret = wait_for((DSI_PORT_READ(STAT) & stat_ulps) == stat_ulps, 200); > + if (ret) { > + dev_warn(&dsi->pdev->dev, > + "Timeout waiting for DSI ULPS entry: STAT 0x%08x", > + DSI_PORT_READ(STAT)); > + DSI_PORT_WRITE(PHYC, DSI_PORT_READ(PHYC) & ~phyc_ulps); > + vc4_dsi_latch_ulps(dsi, false); > + return; > + } > + > + /* The DSI module can't be disabled while the module is > + * generating ULPS state. So, to be able to disable the > + * module, we have the AFE latch the ULPS state and continue > + * on to having the module enter STOP. > + */ > + vc4_dsi_latch_ulps(dsi, ulps); > + > + DSI_PORT_WRITE(STAT, stat_stop); > + DSI_PORT_WRITE(PHYC, DSI_PORT_READ(PHYC) & ~phyc_ulps); > + ret = wait_for((DSI_PORT_READ(STAT) & stat_stop) == stat_stop, 200); > + if (ret) { > + dev_warn(&dsi->pdev->dev, > + "Timeout waiting for DSI STOP entry: STAT 0x%08x", > + DSI_PORT_READ(STAT)); > + DSI_PORT_WRITE(PHYC, DSI_PORT_READ(PHYC) & ~phyc_ulps); > + return; > + } > +} > + > +static u32 > +dsi_hs_timing(u32 ui_ns, u32 ns, u32 ui) > +{ > + /* The HS timings have to be rounded up to a multiple of 8 > + * because we're using the byte clock. > + */ > + return roundup(ui + DIV_ROUND_UP(ns, ui_ns), 8); > +} > + > +/* ESC always runs at 100Mhz. */ > +#define ESC_TIME_NS 10 > + > +static u32 > +dsi_esc_timing(u32 ns) > +{ > + return DIV_ROUND_UP(ns, ESC_TIME_NS); > +} > + > +static void vc4_dsi_encoder_disable(struct drm_encoder *encoder) > +{ > + struct vc4_dsi_encoder *vc4_encoder = to_vc4_dsi_encoder(encoder); > + struct vc4_dsi *dsi = vc4_encoder->dsi; > + struct device *dev = &dsi->pdev->dev; > + > + drm_panel_disable(dsi->panel); > + > + vc4_dsi_ulps(dsi, true); > + > + drm_panel_unprepare(dsi->panel); > + > + clk_disable_unprepare(dsi->pll_phy_clock); > + clk_disable_unprepare(dsi->escape_clock); > + clk_disable_unprepare(dsi->pixel_clock); > + > + pm_runtime_put(dev); > +} > + > +static void vc4_dsi_encoder_enable(struct drm_encoder *encoder) > +{ > + struct drm_display_mode *mode = &encoder->crtc->mode; > + struct vc4_dsi_encoder *vc4_encoder = to_vc4_dsi_encoder(encoder); > + struct vc4_dsi *dsi = vc4_encoder->dsi; > + struct device *dev = &dsi->pdev->dev; > + u32 format = 0, divider = 0; > + bool debug_dump_regs = false; > + unsigned long hs_clock; > + u32 ui_ns; > + /* Minimum LP state duration in escape clock cycles. */ > + u32 lpx = dsi_esc_timing(60); > + unsigned long pixel_clock_hz = mode->clock * 1000; > + unsigned long dsip_clock; > + unsigned long phy_clock; > + int ret; > + > + ret = pm_runtime_get_sync(dev); > + if (ret) { > + DRM_ERROR("Failed to runtime PM enable on DSI%d\n", dsi->port); > + return; > + } > + > + ret = drm_panel_prepare(dsi->panel); > + if (ret) { > + DRM_ERROR("Panel failed to prepare\n"); > + return; > + } > + > + if (debug_dump_regs) { > + DRM_INFO("DSI regs before:\n"); > + vc4_dsi_dump_regs(dsi); > + } > + > + switch (dsi->format) { > + case MIPI_DSI_FMT_RGB888: > + format = DSI_PFORMAT_RGB888; > + divider = 24 / dsi->lanes; > + break; > + case MIPI_DSI_FMT_RGB666: > + format = DSI_PFORMAT_RGB666; > + divider = 24 / dsi->lanes; > + break; > + case MIPI_DSI_FMT_RGB666_PACKED: > + format = DSI_PFORMAT_RGB666_PACKED; > + divider = 18 / dsi->lanes; > + break; > + case MIPI_DSI_FMT_RGB565: > + format = DSI_PFORMAT_RGB565; > + divider = 16 / dsi->lanes; > + break; > + } > + > + phy_clock = pixel_clock_hz * divider; > + ret = clk_set_rate(dsi->pll_phy_clock, phy_clock); > + if (ret) { > + dev_err(&dsi->pdev->dev, > + "Failed to set phy clock to %ld: %d\n", phy_clock, ret); > + } > + > + /* Reset the DSI and all its fifos. */ > + DSI_PORT_WRITE(CTRL, > + DSI_CTRL_SOFT_RESET_CFG | > + DSI_PORT_BIT(CTRL_RESET_FIFOS)); > + > + DSI_PORT_WRITE(CTRL, > + DSI_CTRL_HSDT_EOT_DISABLE | > + DSI_CTRL_RX_LPDT_EOT_DISABLE); > + > + /* Clear all stat bits so we see what has happened during enable. */ > + DSI_PORT_WRITE(STAT, DSI_PORT_READ(STAT)); > + > + /* Set AFE CTR00/CTR1 to release powerdown of analog. */ > + if (dsi->port == 0) { > + u32 afec0 = (VC4_SET_FIELD(7, DSI_PHY_AFEC0_PTATADJ) | > + VC4_SET_FIELD(7, DSI_PHY_AFEC0_CTATADJ)); > + > + if (dsi->lanes < 2) > + afec0 |= DSI0_PHY_AFEC0_PD_DLANE1; > + > + if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO)) > + afec0 |= DSI0_PHY_AFEC0_RESET; > + > + DSI_PORT_WRITE(PHY_AFEC0, afec0); > + > + DSI_PORT_WRITE(PHY_AFEC1, > + VC4_SET_FIELD(6, DSI0_PHY_AFEC1_IDR_DLANE1) | > + VC4_SET_FIELD(6, DSI0_PHY_AFEC1_IDR_DLANE0) | > + VC4_SET_FIELD(6, DSI0_PHY_AFEC1_IDR_CLANE)); > + } else { > + u32 afec0 = (VC4_SET_FIELD(7, DSI_PHY_AFEC0_PTATADJ) | > + VC4_SET_FIELD(7, DSI_PHY_AFEC0_CTATADJ) | > + VC4_SET_FIELD(6, DSI1_PHY_AFEC0_IDR_CLANE) | > + VC4_SET_FIELD(6, DSI1_PHY_AFEC0_IDR_DLANE0) | > + VC4_SET_FIELD(6, DSI1_PHY_AFEC0_IDR_DLANE1) | > + VC4_SET_FIELD(6, DSI1_PHY_AFEC0_IDR_DLANE2) | > + VC4_SET_FIELD(6, DSI1_PHY_AFEC0_IDR_DLANE3)); > + > + if (dsi->lanes < 4) > + afec0 |= DSI1_PHY_AFEC0_PD_DLANE3; > + if (dsi->lanes < 3) > + afec0 |= DSI1_PHY_AFEC0_PD_DLANE2; > + if (dsi->lanes < 2) > + afec0 |= DSI1_PHY_AFEC0_PD_DLANE1; > + > + afec0 |= DSI1_PHY_AFEC0_RESET; > + > + DSI_PORT_WRITE(PHY_AFEC0, afec0); > + > + DSI_PORT_WRITE(PHY_AFEC1, 0); > + > + /* AFEC reset hold time */ > + mdelay(1); > + } > + > + ret = clk_prepare_enable(dsi->escape_clock); > + if (ret) { > + DRM_ERROR("Failed to turn on DSI escape clock: %d\n", ret); > + return; > + } > + > + ret = clk_prepare_enable(dsi->pll_phy_clock); > + if (ret) { > + DRM_ERROR("Failed to turn on DSI PLL: %d\n", ret); > + return; > + } > + > + hs_clock = clk_get_rate(dsi->pll_phy_clock); > + > + /* Yes, we set the DSI0P/DSI1P pixel clock to the byte rate, > + * not the pixel clock rate. DSIxP take from the APHY's byte, > + * DDR2, or DDR4 clock (we use byte) and feed into the PV at > + * that rate. Separately, a value derived from PIX_CLK_DIV > + * and HS_CLKC is fed into the PV to divide down to the actual > + * pixel clock for pushing pixels into DSI. > + */ > + dsip_clock = phy_clock / 8; > + ret = clk_set_rate(dsi->pixel_clock, dsip_clock); > + if (ret) { > + dev_err(dev, "Failed to set pixel clock to %ldHz: %d\n", > + dsip_clock, ret); > + } > + > + ret = clk_prepare_enable(dsi->pixel_clock); > + if (ret) { > + DRM_ERROR("Failed to turn on DSI pixel clock: %d\n", ret); > + return; > + } > + > + /* How many ns one DSI unit interval is. Note that the clock > + * is DDR, so there's an extra divide by 2. > + */ > + ui_ns = DIV_ROUND_UP(500000000, hs_clock); > + > + DSI_PORT_WRITE(HS_CLT0, > + VC4_SET_FIELD(dsi_hs_timing(ui_ns, 262, 0), > + DSI_HS_CLT0_CZERO) | > + VC4_SET_FIELD(dsi_hs_timing(ui_ns, 0, 8), > + DSI_HS_CLT0_CPRE) | > + VC4_SET_FIELD(dsi_hs_timing(ui_ns, 38, 0), > + DSI_HS_CLT0_CPREP)); > + > + DSI_PORT_WRITE(HS_CLT1, > + VC4_SET_FIELD(dsi_hs_timing(ui_ns, 60, 0), > + DSI_HS_CLT1_CTRAIL) | > + VC4_SET_FIELD(dsi_hs_timing(ui_ns, 60, 52), > + DSI_HS_CLT1_CPOST)); > + > + DSI_PORT_WRITE(HS_CLT2, > + VC4_SET_FIELD(dsi_hs_timing(ui_ns, 1000000, 0), > + DSI_HS_CLT2_WUP)); > + > + DSI_PORT_WRITE(HS_DLT3, > + VC4_SET_FIELD(dsi_hs_timing(ui_ns, 100, 0), > + DSI_HS_DLT3_EXIT) | > + VC4_SET_FIELD(dsi_hs_timing(ui_ns, 105, 6), > + DSI_HS_DLT3_ZERO) | > + VC4_SET_FIELD(dsi_hs_timing(ui_ns, 40, 4), > + DSI_HS_DLT3_PRE)); > + > + DSI_PORT_WRITE(HS_DLT4, > + VC4_SET_FIELD(dsi_hs_timing(ui_ns, lpx * ESC_TIME_NS, 0), > + DSI_HS_DLT4_LPX) | > + VC4_SET_FIELD(max(dsi_hs_timing(ui_ns, 0, 8), > + dsi_hs_timing(ui_ns, 60, 4)), > + DSI_HS_DLT4_TRAIL) | > + VC4_SET_FIELD(0, DSI_HS_DLT4_ANLAT)); > + > + DSI_PORT_WRITE(HS_DLT5, VC4_SET_FIELD(dsi_hs_timing(ui_ns, 1000, 5000), > + DSI_HS_DLT5_INIT)); > + > + DSI_PORT_WRITE(HS_DLT6, > + VC4_SET_FIELD(lpx * 5, DSI_HS_DLT6_TA_GET) | > + VC4_SET_FIELD(lpx, DSI_HS_DLT6_TA_SURE) | > + VC4_SET_FIELD(lpx * 4, DSI_HS_DLT6_TA_GO) | > + VC4_SET_FIELD(lpx, DSI_HS_DLT6_LP_LPX)); > + > + DSI_PORT_WRITE(HS_DLT7, > + VC4_SET_FIELD(dsi_esc_timing(1000000), > + DSI_HS_DLT7_LP_WUP)); > + > + DSI_PORT_WRITE(PHYC, > + DSI_PHYC_DLANE0_ENABLE | > + (dsi->lanes >= 2 ? DSI_PHYC_DLANE1_ENABLE : 0) | > + (dsi->lanes >= 3 ? DSI_PHYC_DLANE2_ENABLE : 0) | > + (dsi->lanes >= 4 ? DSI_PHYC_DLANE3_ENABLE : 0) | > + DSI_PORT_BIT(PHYC_CLANE_ENABLE) | > + ((dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) ? > + 0 : DSI_PORT_BIT(PHYC_HS_CLK_CONTINUOUS)) | > + (dsi->port == 0 ? > + VC4_SET_FIELD(lpx - 1, DSI0_PHYC_ESC_CLK_LPDT) : > + VC4_SET_FIELD(lpx - 1, DSI1_PHYC_ESC_CLK_LPDT))); > + > + DSI_PORT_WRITE(CTRL, > + DSI_PORT_READ(CTRL) | > + DSI_CTRL_CAL_BYTE); > + > + /* HS timeout in HS clock cycles: disabled. */ > + DSI_PORT_WRITE(HSTX_TO_CNT, 0); > + /* LP receive timeout in HS clocks. */ > + DSI_PORT_WRITE(LPRX_TO_CNT, 0xffffff); > + /* Bus turnaround timeout */ > + DSI_PORT_WRITE(TA_TO_CNT, 100000); > + /* Display reset sequence timeout */ > + DSI_PORT_WRITE(PR_TO_CNT, 100000); > + > + if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) { > + DSI_PORT_WRITE(DISP0_CTRL, > + VC4_SET_FIELD(divider, DSI_DISP0_PIX_CLK_DIV) | > + VC4_SET_FIELD(format, DSI_DISP0_PFORMAT) | > + VC4_SET_FIELD(DSI_DISP0_LP_STOP_PERFRAME, > + DSI_DISP0_LP_STOP_CTRL) | > + DSI_DISP0_ST_END | > + DSI_DISP0_ENABLE); > + } else { > + DSI_PORT_WRITE(DISP0_CTRL, > + DSI_DISP0_COMMAND_MODE | > + DSI_DISP0_ENABLE); > + } > + > + /* Set up DISP1 for transferring long command payloads through > + * the pixfifo. > + */ > + DSI_PORT_WRITE(DISP1_CTRL, > + VC4_SET_FIELD(DSI_DISP1_PFORMAT_32BIT_LE, > + DSI_DISP1_PFORMAT) | > + DSI_DISP1_ENABLE); > + > + /* Ungate the block. */ > + if (dsi->port == 0) > + DSI_PORT_WRITE(CTRL, DSI_PORT_READ(CTRL) | DSI0_CTRL_CTRL0); > + else > + DSI_PORT_WRITE(CTRL, DSI_PORT_READ(CTRL) | DSI1_CTRL_EN); > + > + /* Bring AFE out of reset. */ > + if (dsi->port == 0) { > + } else { > + DSI_PORT_WRITE(PHY_AFEC0, > + DSI_PORT_READ(PHY_AFEC0) & > + ~DSI1_PHY_AFEC0_RESET); > + } > + > + vc4_dsi_ulps(dsi, false); > + > + if (debug_dump_regs) { > + DRM_INFO("DSI regs after:\n"); > + vc4_dsi_dump_regs(dsi); > + } > + > + ret = drm_panel_enable(dsi->panel); > + if (ret) { > + DRM_ERROR("Panel failed to enable\n"); > + drm_panel_unprepare(dsi->panel); > + return; > + } > +} > + > +static ssize_t vc4_dsi_host_transfer(struct mipi_dsi_host *host, > + const struct mipi_dsi_msg *msg) > +{ > + struct vc4_dsi *dsi = host_to_dsi(host); > + struct mipi_dsi_packet packet; > + u32 pkth = 0, pktc = 0; > + int i, ret; > + bool is_long = mipi_dsi_packet_format_is_long(msg->type); > + u32 cmd_fifo_len = 0, pix_fifo_len = 0; > + > + mipi_dsi_create_packet(&packet, msg); > + > + pkth |= VC4_SET_FIELD(packet.header[0], DSI_TXPKT1H_BC_DT); > + pkth |= VC4_SET_FIELD(packet.header[1] | > + (packet.header[2] << 8), > + DSI_TXPKT1H_BC_PARAM); > + if (is_long) { > + /* Divide data across the various FIFOs we have available. > + * The command FIFO takes byte-oriented data, but is of > + * limited size. The pixel FIFO (never actually used for > + * pixel data in reality) is word oriented, and substantially > + * larger. So, we use the pixel FIFO for most of the data, > + * sending the residual bytes in the command FIFO at the start. > + * > + * With this arrangement, the command FIFO will never get full. > + */ I wondered whether this is something the dsi core should maybe optionally do, but doesn't seem to be a common pattern looking at existing transfer functions. > + if (packet.payload_length <= 16) { > + cmd_fifo_len = packet.payload_length; > + pix_fifo_len = 0; > + } else { > + cmd_fifo_len = (packet.payload_length % > + DSI_PIX_FIFO_WIDTH); > + pix_fifo_len = ((packet.payload_length - cmd_fifo_len) / > + DSI_PIX_FIFO_WIDTH); > + } > + > + WARN_ON_ONCE(pix_fifo_len >= DSI_PIX_FIFO_DEPTH); > + > + pkth |= VC4_SET_FIELD(cmd_fifo_len, DSI_TXPKT1H_BC_CMDFIFO); > + } > + > + if (msg->rx_len) { > + pktc |= VC4_SET_FIELD(DSI_TXPKT1C_CMD_CTRL_RX, > + DSI_TXPKT1C_CMD_CTRL); > + } else { > + pktc |= VC4_SET_FIELD(DSI_TXPKT1C_CMD_CTRL_TX, > + DSI_TXPKT1C_CMD_CTRL); > + } > + > + for (i = 0; i < cmd_fifo_len; i++) > + DSI_PORT_WRITE(TXPKT_CMD_FIFO, packet.payload[i]); > + for (i = 0; i < pix_fifo_len; i++) { > + const u8 *pix = packet.payload + cmd_fifo_len + i * 4; > + > + DSI_PORT_WRITE(TXPKT_PIX_FIFO, > + pix[0] | > + pix[1] << 8 | > + pix[2] << 16 | > + pix[3] << 24); > + } > + > + if (msg->flags & MIPI_DSI_MSG_USE_LPM) > + pktc |= DSI_TXPKT1C_CMD_MODE_LP; > + if (is_long) > + pktc |= DSI_TXPKT1C_CMD_TYPE_LONG; > + > + /* Send one copy of the packet. Larger repeats are used for pixel > + * data in command mode. > + */ > + pktc |= VC4_SET_FIELD(1, DSI_TXPKT1C_CMD_REPEAT); > + > + pktc |= DSI_TXPKT1C_CMD_EN; > + if (pix_fifo_len) { > + pktc |= VC4_SET_FIELD(DSI_TXPKT1C_DISPLAY_NO_SECONDARY, > + DSI_TXPKT1C_DISPLAY_NO); > + } else { > + pktc |= VC4_SET_FIELD(DSI_TXPKT1C_DISPLAY_NO_SHORT, > + DSI_TXPKT1C_DISPLAY_NO); > + } > + > + /* Enable the appropriate interrupt for the transfer completion. */ > + dsi->xfer_result = 0; > + reinit_completion(&dsi->xfer_completion); > + DSI_PORT_WRITE(INT_STAT, DSI1_INT_TXPKT1_DONE | DSI1_INT_PHY_DIR_RTF); > + if (msg->rx_len) { > + DSI_PORT_WRITE(INT_EN, (DSI1_INTERRUPTS_ALWAYS_ENABLED | > + DSI1_INT_PHY_DIR_RTF)); > + } else { > + DSI_PORT_WRITE(INT_EN, (DSI1_INTERRUPTS_ALWAYS_ENABLED | > + DSI1_INT_TXPKT1_DONE)); > + } > + > + /* Send the packet. */ > + DSI_PORT_WRITE(TXPKT1H, pkth); > + DSI_PORT_WRITE(TXPKT1C, pktc); > + > + if (!wait_for_completion_timeout(&dsi->xfer_completion, > + msecs_to_jiffies(1000))) { > + dev_err(&dsi->pdev->dev, "transfer interrupt wait timeout"); > + dev_err(&dsi->pdev->dev, "instat: 0x%08x\n", > + DSI_PORT_READ(INT_STAT)); > + ret = -ETIMEDOUT; > + } else { > + ret = dsi->xfer_result; > + } > + > + DSI_PORT_WRITE(INT_EN, DSI1_INTERRUPTS_ALWAYS_ENABLED); > + > + if (ret) > + goto reset_fifo_and_return; > + > + if (ret == 0 && msg->rx_len) { > + u32 rxpkt1h = DSI_PORT_READ(RXPKT1H); > + u8 *msg_rx = msg->rx_buf; > + > + if (rxpkt1h & DSI_RXPKT1H_PKT_TYPE_LONG) { > + u32 rxlen = VC4_GET_FIELD(rxpkt1h, > + DSI_RXPKT1H_BC_PARAM); > + > + if (rxlen != msg->rx_len) { > + DRM_ERROR("DSI returned %db, expecting %db\n", > + rxlen, (int)msg->rx_len); > + ret = -ENXIO; > + goto reset_fifo_and_return; > + } > + > + for (i = 0; i < msg->rx_len; i++) > + msg_rx[i] = DSI_READ(DSI1_RXPKT_FIFO); > + } else { > + /* FINISHME: Handle AWER */ > + > + msg_rx[0] = VC4_GET_FIELD(rxpkt1h, > + DSI_RXPKT1H_SHORT_0); > + if (msg->rx_len > 1) { > + msg_rx[1] = VC4_GET_FIELD(rxpkt1h, > + DSI_RXPKT1H_SHORT_1); > + } > + } > + } > + > + return ret; > + > +reset_fifo_and_return: > + DRM_ERROR("DSI transfer failed, resetting: %d\n", ret); > + > + DSI_PORT_WRITE(TXPKT1C, DSI_PORT_READ(TXPKT1C) & ~DSI_TXPKT1C_CMD_EN); > + udelay(1); > + DSI_PORT_WRITE(CTRL, > + DSI_PORT_READ(CTRL) | > + DSI_PORT_BIT(CTRL_RESET_FIFOS)); > + > + DSI_PORT_WRITE(TXPKT1C, 0); > + DSI_PORT_WRITE(INT_EN, DSI1_INTERRUPTS_ALWAYS_ENABLED); > + return ret; > +} > + > +static int vc4_dsi_host_attach(struct mipi_dsi_host *host, > + struct mipi_dsi_device *device) > +{ > + struct vc4_dsi *dsi = host_to_dsi(host); > + int ret = 0; > + > + dsi->lanes = device->lanes; > + dsi->channel = device->channel; > + dsi->format = device->format; > + dsi->mode_flags = device->mode_flags; > + > + if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO)) { > + dev_err(&dsi->pdev->dev, > + "Only VIDEO mode panels supported currently.\n"); > + return 0; > + } > + > + dsi->panel = of_drm_find_panel(device->dev.of_node); > + if (!dsi->panel) > + return 0; > + > + ret = drm_panel_attach(dsi->panel, dsi->connector); > + if (ret != 0) > + return ret; > + > + drm_helper_hpd_irq_event(dsi->connector->dev); > + > + return 0; > +} > + > +static int vc4_dsi_host_detach(struct mipi_dsi_host *host, > + struct mipi_dsi_device *device) > +{ > + struct vc4_dsi *dsi = host_to_dsi(host); > + > + if (dsi->panel) { > + int ret = drm_panel_detach(dsi->panel); > + > + if (ret) > + return ret; > + > + dsi->panel = NULL; > + > + drm_helper_hpd_irq_event(dsi->connector->dev); > + } > + > + return 0; > +} > + > +static const struct mipi_dsi_host_ops vc4_dsi_host_ops = { > + .attach = vc4_dsi_host_attach, > + .detach = vc4_dsi_host_detach, There seems to be a lot of cargo-culting going on with attach/detach, and I get a bit the feeling that refactoring this into a standard way to do it (including the of/dt boilerplate, with an eye towards standardizing the bindinds) would be good. Also, proper kerneldoc for these callbacks instead of the onelines (we can do multiline inline comments now, with formatting!) would be great. > + .transfer = vc4_dsi_host_transfer, hisilicon doesn't even have a transfer function, I guess it works by magic. > +}; > + > +static const struct drm_encoder_helper_funcs vc4_dsi_encoder_helper_funcs = { > + .disable = vc4_dsi_encoder_disable, > + .enable = vc4_dsi_encoder_enable, > +}; > + > +static const struct of_device_id vc4_dsi_dt_match[] = { > + { .compatible = "brcm,bcm2835-dsi1", (void *)(uintptr_t)1 }, > + {} > +}; > + > +static void dsi_handle_error(struct vc4_dsi *dsi, > + irqreturn_t *ret, u32 stat, u32 bit, > + const char *type) > +{ > + if (!(stat & bit)) > + return; > + > + DRM_ERROR("DSI%d: %s error\n", dsi->port, type); > + *ret = IRQ_HANDLED; > +} > + > +static irqreturn_t vc4_dsi_irq_handler(int irq, void *data) > +{ > + struct vc4_dsi *dsi = data; > + u32 stat = DSI_PORT_READ(INT_STAT); > + irqreturn_t ret = IRQ_NONE; > + > + DSI_PORT_WRITE(INT_STAT, stat); > + > + dsi_handle_error(dsi, &ret, stat, > + DSI1_INT_ERR_SYNC_ESC, "LPDT sync"); > + dsi_handle_error(dsi, &ret, stat, > + DSI1_INT_ERR_CONTROL, "data lane 0 sequence"); > + dsi_handle_error(dsi, &ret, stat, > + DSI1_INT_ERR_CONT_LP0, "LP0 contention"); > + dsi_handle_error(dsi, &ret, stat, > + DSI1_INT_ERR_CONT_LP1, "LP1 contention"); > + dsi_handle_error(dsi, &ret, stat, > + DSI1_INT_HSTX_TO, "HSTX timeout"); > + dsi_handle_error(dsi, &ret, stat, > + DSI1_INT_LPRX_TO, "LPRX timeout"); > + dsi_handle_error(dsi, &ret, stat, > + DSI1_INT_TA_TO, "turnaround timeout"); > + dsi_handle_error(dsi, &ret, stat, > + DSI1_INT_PR_TO, "peripheral reset timeout"); > + > + if (stat & (DSI1_INT_TXPKT1_DONE | DSI1_INT_PHY_DIR_RTF)) { > + complete(&dsi->xfer_completion); > + ret = IRQ_HANDLED; > + } else if (stat & DSI1_INT_HSTX_TO) { > + complete(&dsi->xfer_completion); > + dsi->xfer_result = -ETIMEDOUT; > + ret = IRQ_HANDLED; > + } > + > + return ret; > +} > + > +/** > + * Exposes clocks generated by the analog PHY that are consumed by > + * CPRMAN (clk-bcm2835.c). > + */ > +static int > +vc4_dsi_init_phy_clocks(struct vc4_dsi *dsi) > +{ > + struct device *dev = &dsi->pdev->dev; > + const char *parent_name = __clk_get_name(dsi->pll_phy_clock); > + static const struct { > + const char *dsi0_name, *dsi1_name; > + int div; > + } phy_clocks[] = { > + { "dsi0_byte", "dsi1_byte", 8 }, > + { "dsi0_ddr2", "dsi1_ddr2", 4 }, > + { "dsi0_ddr", "dsi1_ddr", 2 }, > + }; > + int i; > + > + dsi->clk_onecell.clk_num = ARRAY_SIZE(phy_clocks); > + dsi->clk_onecell.clks = devm_kcalloc(dev, > + dsi->clk_onecell.clk_num, > + sizeof(*dsi->clk_onecell.clks), > + GFP_KERNEL); > + if (!dsi->clk_onecell.clks) > + return -ENOMEM; > + > + for (i = 0; i < ARRAY_SIZE(phy_clocks); i++) { > + struct clk_fixed_factor *fix = &dsi->phy_clocks[i]; > + struct clk_init_data init; > + struct clk *clk; > + > + /* We just use core fixed factor clock ops for the PHY > + * clocks. The clocks are actually gated by the > + * PHY_AFEC0_DDRCLK_EN bits, which we should be > + * setting if we use the DDR/DDR2 clocks. However, > + * vc4_dsi_encoder_enable() is setting up both AFEC0, > + * setting both our parent DSI PLL's rate and this > + * clock's rate, so it knows if DDR/DDR2 are going to > + * be used and could enable the gates itself. > + */ > + fix->mult = 1; > + fix->div = phy_clocks[i].div; > + fix->hw.init = &init; > + > + memset(&init, 0, sizeof(init)); > + init.parent_names = &parent_name; > + init.num_parents = 1; > + if (dsi->port == 1) > + init.name = phy_clocks[i].dsi1_name; > + else > + init.name = phy_clocks[i].dsi0_name; > + init.ops = &clk_fixed_factor_ops; > + init.flags = CLK_IS_BASIC; > + > + clk = devm_clk_register(dev, &fix->hw); > + if (IS_ERR(clk)) > + return PTR_ERR(clk); > + > + dsi->clk_onecell.clks[i] = clk; > + } > + > + return of_clk_add_provider(dev->of_node, > + of_clk_src_onecell_get, > + &dsi->clk_onecell); > +} > + > +static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) > +{ > + struct platform_device *pdev = to_platform_device(dev); > + struct drm_device *drm = dev_get_drvdata(master); > + struct vc4_dev *vc4 = to_vc4_dev(drm); > + struct vc4_dsi *dsi; > + struct vc4_dsi_encoder *vc4_dsi_encoder; > + const struct of_device_id *match; > + dma_cap_mask_t dma_mask; > + int ret; > + > + dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL); > + if (!dsi) > + return -ENOMEM; > + > + match = of_match_device(vc4_dsi_dt_match, dev); > + if (!match) > + return -ENODEV; > + > + dsi->port = (uintptr_t)match->data; > + > + vc4_dsi_encoder = devm_kzalloc(dev, sizeof(*vc4_dsi_encoder), > + GFP_KERNEL); > + if (!vc4_dsi_encoder) > + return -ENOMEM; > + vc4_dsi_encoder->base.type = VC4_ENCODER_TYPE_DSI1; > + vc4_dsi_encoder->dsi = dsi; > + dsi->encoder = &vc4_dsi_encoder->base.base; > + > + dsi->pdev = pdev; > + dsi->regs = vc4_ioremap_regs(pdev, 0); > + if (IS_ERR(dsi->regs)) > + return PTR_ERR(dsi->regs); > + > + if (DSI_PORT_READ(ID) != DSI_ID_VALUE) { > + dev_err(dev, "Port returned 0x%08x for ID instead of 0x%08x\n", > + DSI_PORT_READ(ID), DSI_ID_VALUE); > + return -ENODEV; > + } > + > + /* DSI1 has a broken AXI slave that doesn't respond to writes > + * from the ARM. It does handle writes from the DMA engine, > + * so set up a channel for talking to it. > + */ > + if (dsi->port == 1) { > + dsi->reg_dma_mem = dma_alloc_coherent(dev, 4, > + &dsi->reg_dma_paddr, > + GFP_KERNEL); > + if (!dsi->reg_dma_mem) { > + DRM_ERROR("Failed to get DMA memory\n"); > + return -ENOMEM; > + } > + > + dma_cap_zero(dma_mask); > + dma_cap_set(DMA_MEMCPY, dma_mask); > + dsi->reg_dma_chan = dma_request_chan_by_mask(&dma_mask); > + if (IS_ERR(dsi->reg_dma_chan)) { > + ret = PTR_ERR(dsi->reg_dma_chan); > + if (ret != -EPROBE_DEFER) > + DRM_ERROR("Failed to get DMA channel: %d\n", > + ret); > + return ret; > + } > + > + /* Get the physical address of the device's registers. The > + * struct resource for the regs gives us the bus address > + * instead. > + */ > + dsi->reg_paddr = be32_to_cpup(of_get_address(dev->of_node, > + 0, NULL, NULL)); > + } > + > + init_completion(&dsi->xfer_completion); > + /* At startup enable error-reporting interrupts and nothing else. */ > + DSI_PORT_WRITE(INT_EN, DSI1_INTERRUPTS_ALWAYS_ENABLED); > + /* Clear any existing interrupt state. */ > + DSI_PORT_WRITE(INT_STAT, DSI_PORT_READ(INT_STAT)); > + > + ret = devm_request_irq(dev, platform_get_irq(pdev, 0), > + vc4_dsi_irq_handler, 0, "vc4 dsi", dsi); > + if (ret) { > + if (ret != -EPROBE_DEFER) > + dev_err(dev, "Failed to get interrupt: %d\n", ret); > + return ret; > + } > + > + dsi->escape_clock = devm_clk_get(dev, "escape"); > + if (IS_ERR(dsi->escape_clock)) { > + ret = PTR_ERR(dsi->escape_clock); > + if (ret != -EPROBE_DEFER) > + dev_err(dev, "Failed to get escape clock: %d\n", ret); > + return ret; > + } > + > + dsi->pll_phy_clock = devm_clk_get(dev, "phy"); > + if (IS_ERR(dsi->pll_phy_clock)) { > + ret = PTR_ERR(dsi->pll_phy_clock); > + if (ret != -EPROBE_DEFER) > + dev_err(dev, "Failed to get phy clock: %d\n", ret); > + return ret; > + } > + > + dsi->pixel_clock = devm_clk_get(dev, "pixel"); > + if (IS_ERR(dsi->pixel_clock)) { > + ret = PTR_ERR(dsi->pixel_clock); > + if (ret != -EPROBE_DEFER) > + dev_err(dev, "Failed to get pixel clock: %d\n", ret); > + return ret; > + } > + > + /* The esc clock rate is supposed to always be 100Mhz. */ > + ret = clk_set_rate(dsi->escape_clock, 100 * 1000000); > + if (ret) { > + dev_err(dev, "Failed to set esc clock: %d\n", ret); > + return ret; > + } > + > + ret = vc4_dsi_init_phy_clocks(dsi); > + if (ret) > + return ret; > + > + if (dsi->port == 1) > + vc4->dsi1 = dsi; > + > + drm_encoder_init(drm, dsi->encoder, &vc4_dsi_encoder_funcs, > + DRM_MODE_ENCODER_DSI, NULL); > + drm_encoder_helper_add(dsi->encoder, &vc4_dsi_encoder_helper_funcs); > + > + dsi->connector = vc4_dsi_connector_init(drm, dsi); > + if (IS_ERR(dsi->connector)) { > + ret = PTR_ERR(dsi->connector); > + goto err_destroy_encoder; > + } > + > + dsi->dsi_host.ops = &vc4_dsi_host_ops; > + dsi->dsi_host.dev = dev; > + > + mipi_dsi_host_register(&dsi->dsi_host); > + > + dev_set_drvdata(dev, dsi); > + > + pm_runtime_enable(dev); > + > + return 0; > + > +err_destroy_encoder: > + vc4_dsi_encoder_destroy(dsi->encoder); > + > + return ret; > +} > + > +static void vc4_dsi_unbind(struct device *dev, struct device *master, > + void *data) > +{ > + struct drm_device *drm = dev_get_drvdata(master); > + struct vc4_dev *vc4 = to_vc4_dev(drm); > + struct vc4_dsi *dsi = dev_get_drvdata(dev); > + > + pm_runtime_disable(dev); > + > + vc4_dsi_connector_destroy(dsi->connector); > + vc4_dsi_encoder_destroy(dsi->encoder); > + > + mipi_dsi_host_unregister(&dsi->dsi_host); > + > + clk_disable_unprepare(dsi->pll_phy_clock); > + clk_disable_unprepare(dsi->escape_clock); > + > + if (dsi->port == 1) > + vc4->dsi1 = NULL; > +} > + > +static const struct component_ops vc4_dsi_ops = { > + .bind = vc4_dsi_bind, > + .unbind = vc4_dsi_unbind, > +}; > + > +static int vc4_dsi_dev_probe(struct platform_device *pdev) > +{ > + return component_add(&pdev->dev, &vc4_dsi_ops); > +} > + > +static int vc4_dsi_dev_remove(struct platform_device *pdev) > +{ > + component_del(&pdev->dev, &vc4_dsi_ops); > + return 0; > +} > + > +struct platform_driver vc4_dsi_driver = { > + .probe = vc4_dsi_dev_probe, > + .remove = vc4_dsi_dev_remove, > + .driver = { > + .name = "vc4_dsi", > + .of_match_table = vc4_dsi_dt_match, > + }, > +}; > -- > 2.11.0 > > _______________________________________________ > dri-devel mailing list > dri-devel at lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/dri-devel -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch From mboxrd@z Thu Jan 1 00:00:00 1970 From: Daniel Vetter Subject: Re: [PATCH 07/11] drm/vc4: Add DSI driver Date: Tue, 31 Jan 2017 20:51:59 +0100 Message-ID: <20170131195159.kfqfmvtngxzvt63a@phenom.ffwll.local> References: <20161214194621.16499-1-eric@anholt.net> <20161214194621.16499-8-eric@anholt.net> Mime-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Return-path: Received: from mail-wm0-x241.google.com (mail-wm0-x241.google.com [IPv6:2a00:1450:400c:c09::241]) by gabe.freedesktop.org (Postfix) with ESMTPS id C7A29890E5 for ; Tue, 31 Jan 2017 19:52:04 +0000 (UTC) Received: by mail-wm0-x241.google.com with SMTP id c85so527747wmi.1 for ; Tue, 31 Jan 2017 11:52:04 -0800 (PST) Content-Disposition: inline In-Reply-To: <20161214194621.16499-8-eric@anholt.net> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" To: Eric Anholt Cc: Mark Rutland , Florian Fainelli , Stephen Warren , Michael Turquette , Lee Jones , Stephen Boyd , linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, Rob Herring , linux-rpi-kernel@lists.infradead.org, bcm-kernel-feedback-list@broadcom.com, linux-clk@vger.kernel.org, linux-arm-kernel@lists.infradead.org List-Id: dri-devel@lists.freedesktop.org T24gV2VkLCBEZWMgMTQsIDIwMTYgYXQgMTE6NDY6MTdBTSAtMDgwMCwgRXJpYyBBbmhvbHQgd3Jv dGU6Cj4gVGhlIERTSTAgYW5kIERTSTEgYmxvY2tzIG9uIHRoZSAyODM1IGFyZSByZWxhdGVkIGhh cmR3YXJlIGJsb2Nrcy4KPiBTb21lIHJlZ2lzdGVycyBtb3ZlIGFyb3VuZCwgYW5kIHRoZSBmZWF0 dXJlc2V0IGlzIHNsaWdodGx5IGRpZmZlcmVudCwKPiBhcyBEU0kxICh0aGUgNC1sYW5lIERTSSkg aXMgYSBsYXRlciB2ZXJzaW9uIG9mIHRoZSBoYXJkd2FyZSBibG9jay4KPiBUaGlzIGRyaXZlciBk b2Vzbid0IHlldCBlbmFibGUgRFNJMCwgc2luY2Ugd2UgZG9uJ3QgaGF2ZSBhbnkgaGFyZHdhcmUK PiB0byB0ZXN0IGFnYWluc3QsIGJ1dCBpdCBkb2VzIHB1dCBhIGxvdCBvZiB0aGUgcmVnaXN0ZXIg ZGVmaW5pdGlvbnMgYW5kCj4gY29kZSBpbiBwbGFjZS4KPiAKPiBTaWduZWQtb2ZmLWJ5OiBFcmlj IEFuaG9sdCA8ZXJpY0BhbmhvbHQubmV0PgoKTG9va3MgYWxsIG5lYXQsIGJlbG93IGEgZmV3IHNl bWktcmFuZG9tIGlkZWFzLgoKQWNrZWQtYnk6IERhbmllbCBWZXR0ZXIgPGRhbmllbC52ZXR0ZXJA ZmZ3bGwuY2g+Cj4gLS0tCj4gIGRyaXZlcnMvZ3B1L2RybS92YzQvS2NvbmZpZyAgICAgICB8ICAg IDIgKwo+ICBkcml2ZXJzL2dwdS9kcm0vdmM0L01ha2VmaWxlICAgICAgfCAgICAxICsKPiAgZHJp dmVycy9ncHUvZHJtL3ZjNC92YzRfZGVidWdmcy5jIHwgICAgMSArCj4gIGRyaXZlcnMvZ3B1L2Ry bS92YzQvdmM0X2Rydi5jICAgICB8ICAgIDEgKwo+ICBkcml2ZXJzL2dwdS9kcm0vdmM0L3ZjNF9k cnYuaCAgICAgfCAgICA1ICsKPiAgZHJpdmVycy9ncHUvZHJtL3ZjNC92YzRfZHNpLmMgICAgIHwg MTcyNSArKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrCj4gIDYgZmlsZXMgY2hh bmdlZCwgMTczNSBpbnNlcnRpb25zKCspCj4gIGNyZWF0ZSBtb2RlIDEwMDY0NCBkcml2ZXJzL2dw dS9kcm0vdmM0L3ZjNF9kc2kuYwo+IAo+IGRpZmYgLS1naXQgYS9kcml2ZXJzL2dwdS9kcm0vdmM0 L0tjb25maWcgYi9kcml2ZXJzL2dwdS9kcm0vdmM0L0tjb25maWcKPiBpbmRleCBlNTNkZjU5Y2Ix MzkuLmUxNTE3ZDA3Y2I3ZCAxMDA2NDQKPiAtLS0gYS9kcml2ZXJzL2dwdS9kcm0vdmM0L0tjb25m aWcKPiArKysgYi9kcml2ZXJzL2dwdS9kcm0vdmM0L0tjb25maWcKPiBAQCAtMiwxMCArMiwxMiBA QCBjb25maWcgRFJNX1ZDNAo+ICAJdHJpc3RhdGUgIkJyb2FkY29tIFZDNCBHcmFwaGljcyIKPiAg CWRlcGVuZHMgb24gQVJDSF9CQ00yODM1IHx8IENPTVBJTEVfVEVTVAo+ICAJZGVwZW5kcyBvbiBE Uk0KPiArCWRlcGVuZHMgb24gQ09NTU9OX0NMSwo+ICAJc2VsZWN0IERSTV9LTVNfSEVMUEVSCj4g IAlzZWxlY3QgRFJNX0tNU19DTUFfSEVMUEVSCj4gIAlzZWxlY3QgRFJNX0dFTV9DTUFfSEVMUEVS Cj4gIAlzZWxlY3QgRFJNX1BBTkVMCj4gKwlzZWxlY3QgRFJNX01JUElfRFNJCj4gIAloZWxwCj4g IAkgIENob29zZSB0aGlzIG9wdGlvbiBpZiB5b3UgaGF2ZSBhIHN5c3RlbSB0aGF0IGhhcyBhIEJy b2FkY29tCj4gIAkgIFZDNCBHUFUsIHN1Y2ggYXMgdGhlIFJhc3BiZXJyeSBQaSBvciBvdGhlciBC Q00yNzA4L0JDTTI4MzUuCj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvZ3B1L2RybS92YzQvTWFrZWZp bGUgYi9kcml2ZXJzL2dwdS9kcm0vdmM0L01ha2VmaWxlCj4gaW5kZXggNzc1N2Y2OWE4YTc3Li42 MWY0NWQxMjJiZDAgMTAwNjQ0Cj4gLS0tIGEvZHJpdmVycy9ncHUvZHJtL3ZjNC9NYWtlZmlsZQo+ ICsrKyBiL2RyaXZlcnMvZ3B1L2RybS92YzQvTWFrZWZpbGUKPiBAQCAtOCw2ICs4LDcgQEAgdmM0 LXkgOj0gXAo+ICAJdmM0X2NydGMubyBcCj4gIAl2YzRfZHJ2Lm8gXAo+ICAJdmM0X2RwaS5vIFwK PiArCXZjNF9kc2kubyBcCj4gIAl2YzRfa21zLm8gXAo+ICAJdmM0X2dlbS5vIFwKPiAgCXZjNF9o ZG1pLm8gXAo+IGRpZmYgLS1naXQgYS9kcml2ZXJzL2dwdS9kcm0vdmM0L3ZjNF9kZWJ1Z2ZzLmMg Yi9kcml2ZXJzL2dwdS9kcm0vdmM0L3ZjNF9kZWJ1Z2ZzLmMKPiBpbmRleCBjYWY4MTdiYWM4ODUu LjNjYTQ3NmM2ZTA1NyAxMDA2NDQKPiAtLS0gYS9kcml2ZXJzL2dwdS9kcm0vdmM0L3ZjNF9kZWJ1 Z2ZzLmMKPiArKysgYi9kcml2ZXJzL2dwdS9kcm0vdmM0L3ZjNF9kZWJ1Z2ZzLmMKPiBAQCAtMTgs NiArMTgsNyBAQAo+ICBzdGF0aWMgY29uc3Qgc3RydWN0IGRybV9pbmZvX2xpc3QgdmM0X2RlYnVn ZnNfbGlzdFtdID0gewo+ICAJeyJib19zdGF0cyIsIHZjNF9ib19zdGF0c19kZWJ1Z2ZzLCAwfSwK PiAgCXsiZHBpX3JlZ3MiLCB2YzRfZHBpX2RlYnVnZnNfcmVncywgMH0sCj4gKwl7ImRzaTFfcmVn cyIsIHZjNF9kc2lfZGVidWdmc19yZWdzLCAwLCAodm9pZCAqKSh1aW50cHRyX3QpMX0sCj4gIAl7 ImhkbWlfcmVncyIsIHZjNF9oZG1pX2RlYnVnZnNfcmVncywgMH0sCj4gIAl7InZlY19yZWdzIiwg dmM0X3ZlY19kZWJ1Z2ZzX3JlZ3MsIDB9LAo+ICAJeyJodnNfcmVncyIsIHZjNF9odnNfZGVidWdm c19yZWdzLCAwfSwKPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9ncHUvZHJtL3ZjNC92YzRfZHJ2LmMg Yi9kcml2ZXJzL2dwdS9kcm0vdmM0L3ZjNF9kcnYuYwo+IGluZGV4IGJkYWIzMzM5NzlkYy4uMmQy ZWRjN2RjZjRhIDEwMDY0NAo+IC0tLSBhL2RyaXZlcnMvZ3B1L2RybS92YzQvdmM0X2Rydi5jCj4g KysrIGIvZHJpdmVycy9ncHUvZHJtL3ZjNC92YzRfZHJ2LmMKPiBAQCAtMjk4LDYgKzI5OCw3IEBA IHN0YXRpYyBzdHJ1Y3QgcGxhdGZvcm1fZHJpdmVyICpjb25zdCBjb21wb25lbnRfZHJpdmVyc1td ID0gewo+ICAJJnZjNF9oZG1pX2RyaXZlciwKPiAgCSZ2YzRfdmVjX2RyaXZlciwKPiAgCSZ2YzRf ZHBpX2RyaXZlciwKPiArCSZ2YzRfZHNpX2RyaXZlciwKPiAgCSZ2YzRfaHZzX2RyaXZlciwKPiAg CSZ2YzRfY3J0Y19kcml2ZXIsCj4gIAkmdmM0X3YzZF9kcml2ZXIsCj4gZGlmZiAtLWdpdCBhL2Ry aXZlcnMvZ3B1L2RybS92YzQvdmM0X2Rydi5oIGIvZHJpdmVycy9ncHUvZHJtL3ZjNC92YzRfZHJ2 LmgKPiBpbmRleCBiNWM0YmIxNGQwZDEuLjcyM2YwZWM5NDBhYyAxMDA2NDQKPiAtLS0gYS9kcml2 ZXJzL2dwdS9kcm0vdmM0L3ZjNF9kcnYuaAo+ICsrKyBiL2RyaXZlcnMvZ3B1L2RybS92YzQvdmM0 X2Rydi5oCj4gQEAgLTE3LDYgKzE3LDcgQEAgc3RydWN0IHZjNF9kZXYgewo+ICAJc3RydWN0IHZj NF9jcnRjICpjcnRjWzNdOwo+ICAJc3RydWN0IHZjNF92M2QgKnYzZDsKPiAgCXN0cnVjdCB2YzRf ZHBpICpkcGk7Cj4gKwlzdHJ1Y3QgdmM0X2RzaSAqZHNpMTsKPiAgCXN0cnVjdCB2YzRfdmVjICp2 ZWM7Cj4gIAo+ICAJc3RydWN0IGRybV9mYmRldl9jbWEgKmZiZGV2Owo+IEBAIC00NjUsNiArNDY2 LDEwIEBAIHZvaWQgX19pb21lbSAqdmM0X2lvcmVtYXBfcmVncyhzdHJ1Y3QgcGxhdGZvcm1fZGV2 aWNlICpkZXYsIGludCBpbmRleCk7Cj4gIGV4dGVybiBzdHJ1Y3QgcGxhdGZvcm1fZHJpdmVyIHZj NF9kcGlfZHJpdmVyOwo+ICBpbnQgdmM0X2RwaV9kZWJ1Z2ZzX3JlZ3Moc3RydWN0IHNlcV9maWxl ICptLCB2b2lkICp1bnVzZWQpOwo+ICAKPiArLyogdmM0X2RzaS5jICovCj4gK2V4dGVybiBzdHJ1 Y3QgcGxhdGZvcm1fZHJpdmVyIHZjNF9kc2lfZHJpdmVyOwo+ICtpbnQgdmM0X2RzaV9kZWJ1Z2Zz X3JlZ3Moc3RydWN0IHNlcV9maWxlICptLCB2b2lkICp1bnVzZWQpOwo+ICsKPiAgLyogdmM0X2dl bS5jICovCj4gIHZvaWQgdmM0X2dlbV9pbml0KHN0cnVjdCBkcm1fZGV2aWNlICpkZXYpOwo+ICB2 b2lkIHZjNF9nZW1fZGVzdHJveShzdHJ1Y3QgZHJtX2RldmljZSAqZGV2KTsKPiBkaWZmIC0tZ2l0 IGEvZHJpdmVycy9ncHUvZHJtL3ZjNC92YzRfZHNpLmMgYi9kcml2ZXJzL2dwdS9kcm0vdmM0L3Zj NF9kc2kuYwo+IG5ldyBmaWxlIG1vZGUgMTAwNjQ0Cj4gaW5kZXggMDAwMDAwMDAwMDAwLi4xN2Zj YWMzODFkYmIKPiAtLS0gL2Rldi9udWxsCj4gKysrIGIvZHJpdmVycy9ncHUvZHJtL3ZjNC92YzRf ZHNpLmMKPiBAQCAtMCwwICsxLDE3MjUgQEAKPiArLyoKPiArICogQ29weXJpZ2h0IChDKSAyMDE2 IEJyb2FkY29tCj4gKyAqCj4gKyAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOyB5b3Ug Y2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5IGl0Cj4gKyAqIHVuZGVyIHRoZSB0ZXJt cyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgdmVyc2lvbiAyIGFzIHB1Ymxpc2hl ZCBieQo+ICsgKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLgo+ICsgKgo+ICsgKiBUaGlz IHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1 bCwgYnV0IFdJVEhPVVQKPiArICogQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxp ZWQgd2FycmFudHkgb2YgTUVSQ0hBTlRBQklMSVRZIG9yCj4gKyAqIEZJVE5FU1MgRk9SIEEgUEFS VElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IK PiArICogbW9yZSBkZXRhaWxzLgo+ICsgKgo+ICsgKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQg YSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhbG9uZyB3aXRoCj4gKyAq IHRoaXMgcHJvZ3JhbS4gIElmIG5vdCwgc2VlIDxodHRwOi8vd3d3LmdudS5vcmcvbGljZW5zZXMv Pi4KPiArICovCj4gKwo+ICsvKioKPiArICogRE9DOiBWQzQgRFNJMC9EU0kxIG1vZHVsZQoKU2lu Y2UgeW91J3JlIGJvdGhlcmluZyB3aXRoIGtlcm5lbGRvYywgSSBzdHJvbmdseSByZWNvbW1lbmQg eW91IGFkZCBhCnZjNC5yc3QgaW4gRG9jdW1lbnRhdGlvbi9ncHUsIGluY2x1ZGUgaXQgdG9nZXRo ZXIgd2l0aCB0aGUgb3RoZXIgZHJpdmVycwooYXRtIG9ubHkgaTkxNSwgYnV0IE5vcmFsZiB3aWxs IGFkZCBvbmUgZm9yIHRpbnlkcm0pIGFuZCB0aGVuIGFkZCBzdGFuemFzCnRvIHB1bGwgeW91ciBr ZXJuZWxkb2MgaW4uIFRoYXQncyB0aGUgb25seSB3YXkgdG8gbGludCBpdCAoYXQgbGVhc3QgZm9y Cm5vdywgdW50aWwgbWF5YmUgd2UgbWVyZ2UgSmFuaSdzIG1ha2UgdGFyZ2V0IHRvIGxpbnQgYWxs IHRoZSBrZXJuZWxkb2NzKSwKYW5kIEkgdGhpbmsgc2xvd2x5IGJ1aWxkaW5nIHVwIGRyaXZlciBk b2NzIHdvdWxkIGJlIHJlYWxseSBzd2VldC4KCkFueXdheSwganVzdCBhbiBpZGVhIGZvciB0aGUg ZnV0dXJlLgoKPiArICoKPiArICogQkNNMjgzNSBjb250YWlucyB0d28gRFNJIG1vZHVsZXMsIERT STAgYW5kIERTSTEuICBEU0kwIGlzIGEKPiArICogc2luZ2xlLWxhbmUgRFNJIGNvbnRyb2xsZXIs IHdoaWxlIERTSTEgaXMgYSBtb3JlIG1vZGVybiA0LWxhbmUgRFNJCj4gKyAqIGNvbnRyb2xsZXIu Cj4gKyAqCj4gKyAqIE1vc3QgUmFzcGJlcnJ5IFBpIGJvYXJkcyBleHBvc2UgRFNJMSBhcyB0aGVp ciAiRElTUExBWSIgY29ubmVjdG9yLAo+ICsgKiB3aGlsZSB0aGUgY29tcHV0ZSBtb2R1bGUgYnJp bmdzIGJvdGggRFNJMCBhbmQgRFNJMSBvdXQuCj4gKyAqCj4gKyAqIFRoaXMgZHJpdmVyIGhhcyBi ZWVuIHRlc3RlZCBmb3IgRFNJMSB2aWRlby1tb2RlIGRpc3BsYXkgb25seQo+ICsgKiBjdXJyZW50 bHksIHdpdGggbW9zdCBvZiB0aGUgaW5mb3JtYXRpb24gbmVjZXNzYXJ5IGZvciBEU0kwCj4gKyAq IGhvcGVmdWxseSBwcmVzZW50Lgo+ICsgKi8KPiArCj4gKyNpbmNsdWRlICJkcm1fYXRvbWljX2hl bHBlci5oIgo+ICsjaW5jbHVkZSAiZHJtX2NydGNfaGVscGVyLmgiCj4gKyNpbmNsdWRlICJkcm1f ZWRpZC5oIgo+ICsjaW5jbHVkZSAiZHJtX21pcGlfZHNpLmgiCj4gKyNpbmNsdWRlICJkcm1fcGFu ZWwuaCIKPiArI2luY2x1ZGUgImxpbnV4L2Nsay5oIgo+ICsjaW5jbHVkZSAibGludXgvY2xrLXBy b3ZpZGVyLmgiCj4gKyNpbmNsdWRlICJsaW51eC9jb21wbGV0aW9uLmgiCj4gKyNpbmNsdWRlICJs aW51eC9jb21wb25lbnQuaCIKPiArI2luY2x1ZGUgImxpbnV4L2RtYWVuZ2luZS5oIgo+ICsjaW5j bHVkZSAibGludXgvaTJjLmgiCj4gKyNpbmNsdWRlICJsaW51eC9vZl9hZGRyZXNzLmgiCj4gKyNp bmNsdWRlICJsaW51eC9vZl9wbGF0Zm9ybS5oIgo+ICsjaW5jbHVkZSAibGludXgvcG1fcnVudGlt ZS5oIgo+ICsjaW5jbHVkZSAidmM0X2Rydi5oIgo+ICsjaW5jbHVkZSAidmM0X3JlZ3MuaCIKPiAr Cj4gKyNkZWZpbmUgRFNJX0NNRF9GSUZPX0RFUFRIICAxNgo+ICsjZGVmaW5lIERTSV9QSVhfRklG T19ERVBUSCAyNTYKPiArI2RlZmluZSBEU0lfUElYX0ZJRk9fV0lEVEggICA0Cj4gKwo+ICsjZGVm aW5lIERTSTBfQ1RSTAkJMHgwMAo+ICsKPiArLyogQ29tbWFuZCBwYWNrZXQgY29udHJvbC4gKi8K PiArI2RlZmluZSBEU0kwX1RYUEtUMUMJCTB4MDQgLyogQUtBIFBLVEMgKi8KPiArI2RlZmluZSBE U0kxX1RYUEtUMUMJCTB4MDQKPiArIyBkZWZpbmUgRFNJX1RYUEtUMUNfVFJJR19DTURfTUFTSwlW QzRfTUFTSygzMSwgMjQpCj4gKyMgZGVmaW5lIERTSV9UWFBLVDFDX1RSSUdfQ01EX1NISUZUCTI0 Cj4gKyMgZGVmaW5lIERTSV9UWFBLVDFDX0NNRF9SRVBFQVRfTUFTSwlWQzRfTUFTSygyMywgMTAp Cj4gKyMgZGVmaW5lIERTSV9UWFBLVDFDX0NNRF9SRVBFQVRfU0hJRlQJMTAKPiArCj4gKyMgZGVm aW5lIERTSV9UWFBLVDFDX0RJU1BMQVlfTk9fTUFTSwlWQzRfTUFTSyg5LCA4KQo+ICsjIGRlZmlu ZSBEU0lfVFhQS1QxQ19ESVNQTEFZX05PX1NISUZUCTgKPiArLyogU2hvcnQsIHRyaWdnZXIsIEJU QSwgb3IgYSBsb25nIHBhY2tldCB0aGF0IGZpdHMgYWxsIGluIENNREZJRk8uICovCj4gKyMgZGVm aW5lIERTSV9UWFBLVDFDX0RJU1BMQVlfTk9fU0hPUlQJCTAKPiArLyogUHJpbWFyeSBkaXNwbGF5 IHdoZXJlIGNtZGZpZm8gcHJvdmlkZXMgcGFydCBvZiB0aGUgcGF5bG9hZCBhbmQKPiArICogcGl4 ZWx2YWx2ZSB0aGUgcmVzdC4KPiArICovCj4gKyMgZGVmaW5lIERTSV9UWFBLVDFDX0RJU1BMQVlf Tk9fUFJJTUFSWQkJMQo+ICsvKiBTZWNvbmRhcnkgZGlzcGxheSB3aGVyZSBjbWRmaWZvIHByb3Zp ZGVzIHBhcnQgb2YgdGhlIHBheWxvYWQgYW5kCj4gKyAqIHBpeGZpZm8gdGhlIHJlc3QuCj4gKyAq Lwo+ICsjIGRlZmluZSBEU0lfVFhQS1QxQ19ESVNQTEFZX05PX1NFQ09OREFSWQkyCj4gKwo+ICsj IGRlZmluZSBEU0lfVFhQS1QxQ19DTURfVFhfVElNRV9NQVNLCVZDNF9NQVNLKDcsIDYpCj4gKyMg ZGVmaW5lIERTSV9UWFBLVDFDX0NNRF9UWF9USU1FX1NISUZUCTYKPiArCj4gKyMgZGVmaW5lIERT SV9UWFBLVDFDX0NNRF9DVFJMX01BU0sJVkM0X01BU0soNSwgNCkKPiArIyBkZWZpbmUgRFNJX1RY UEtUMUNfQ01EX0NUUkxfU0hJRlQJNAo+ICsvKiBDb21tYW5kIG9ubHkuICBVc2VzIFRYUEtUMUgg YW5kIERJU1BMQVlfTk8gKi8KPiArIyBkZWZpbmUgRFNJX1RYUEtUMUNfQ01EX0NUUkxfVFgJMAo+ ICsvKiBDb21tYW5kIHdpdGggQlRBIGZvciBlaXRoZXIgYWNrIG9yIHJlYWQgZGF0YS4gKi8KPiAr IyBkZWZpbmUgRFNJX1RYUEtUMUNfQ01EX0NUUkxfUlgJMQo+ICsvKiBUcmlnZ2VyIGFjY29yZGlu ZyB0byBUUklHX0NNRCAqLwo+ICsjIGRlZmluZSBEU0lfVFhQS1QxQ19DTURfQ1RSTF9UUklHCTIK PiArLyogQlRBIGFsb25lIGZvciBnZXR0aW5nIGVycm9yIHN0YXR1cyBhZnRlciBhIGNvbW1hbmQs IG9yIGEgVEUgdHJpZ2dlcgo+ICsgKiB3aXRob3V0IGEgcHJldmlvdXMgY29tbWFuZC4KPiArICov Cj4gKyMgZGVmaW5lIERTSV9UWFBLVDFDX0NNRF9DVFJMX0JUQQkzCj4gKwo+ICsjIGRlZmluZSBE U0lfVFhQS1QxQ19DTURfTU9ERV9MUAlCSVQoMykKPiArIyBkZWZpbmUgRFNJX1RYUEtUMUNfQ01E X1RZUEVfTE9ORwlCSVQoMikKPiArIyBkZWZpbmUgRFNJX1RYUEtUMUNfQ01EX1RFX0VOCQlCSVQo MSkKPiArIyBkZWZpbmUgRFNJX1RYUEtUMUNfQ01EX0VOCQlCSVQoMCkKPiArCj4gKy8qIENvbW1h bmQgcGFja2V0IGhlYWRlci4gKi8KPiArI2RlZmluZSBEU0kwX1RYUEtUMUgJCTB4MDggLyogQUtB IFBLVEggKi8KPiArI2RlZmluZSBEU0kxX1RYUEtUMUgJCTB4MDgKPiArIyBkZWZpbmUgRFNJX1RY UEtUMUhfQkNfQ01ERklGT19NQVNLCVZDNF9NQVNLKDMxLCAyNCkKPiArIyBkZWZpbmUgRFNJX1RY UEtUMUhfQkNfQ01ERklGT19TSElGVAkyNAo+ICsjIGRlZmluZSBEU0lfVFhQS1QxSF9CQ19QQVJB TV9NQVNLCVZDNF9NQVNLKDIzLCA4KQo+ICsjIGRlZmluZSBEU0lfVFhQS1QxSF9CQ19QQVJBTV9T SElGVAk4Cj4gKyMgZGVmaW5lIERTSV9UWFBLVDFIX0JDX0RUX01BU0sJCVZDNF9NQVNLKDcsIDAp Cj4gKyMgZGVmaW5lIERTSV9UWFBLVDFIX0JDX0RUX1NISUZUCTAKPiArCj4gKyNkZWZpbmUgRFNJ MF9SWFBLVDFICQkweDBjIC8qIEFLQSBSWDFfUEtUSCAqLwo+ICsjZGVmaW5lIERTSTFfUlhQS1Qx SAkJMHgxNAo+ICsjIGRlZmluZSBEU0lfUlhQS1QxSF9DUkNfRVJSCQlCSVQoMzEpCj4gKyMgZGVm aW5lIERTSV9SWFBLVDFIX0RFVF9FUlIJCUJJVCgzMCkKPiArIyBkZWZpbmUgRFNJX1JYUEtUMUhf RUNDX0VSUgkJQklUKDI5KQo+ICsjIGRlZmluZSBEU0lfUlhQS1QxSF9DT1JfRVJSCQlCSVQoMjgp Cj4gKyMgZGVmaW5lIERTSV9SWFBLVDFIX0lOQ09NUF9QS1QJCUJJVCgyNSkKPiArIyBkZWZpbmUg RFNJX1JYUEtUMUhfUEtUX1RZUEVfTE9ORwlCSVQoMjQpCj4gKy8qIEJ5dGUgY291bnQgaWYgRFNJ X1JYUEtUMUhfUEtUX1RZUEVfTE9ORyAqLwo+ICsjIGRlZmluZSBEU0lfUlhQS1QxSF9CQ19QQVJB TV9NQVNLCVZDNF9NQVNLKDIzLCA4KQo+ICsjIGRlZmluZSBEU0lfUlhQS1QxSF9CQ19QQVJBTV9T SElGVAk4Cj4gKy8qIFNob3J0IHJldHVybiBieXRlcyBpZiAhRFNJX1JYUEtUMUhfUEtUX1RZUEVf TE9ORyAqLwo+ICsjIGRlZmluZSBEU0lfUlhQS1QxSF9TSE9SVF8xX01BU0sJVkM0X01BU0soMjMs IDE2KQo+ICsjIGRlZmluZSBEU0lfUlhQS1QxSF9TSE9SVF8xX1NISUZUCTE2Cj4gKyMgZGVmaW5l IERTSV9SWFBLVDFIX1NIT1JUXzBfTUFTSwlWQzRfTUFTSygxNSwgOCkKPiArIyBkZWZpbmUgRFNJ X1JYUEtUMUhfU0hPUlRfMF9TSElGVAk4Cj4gKyMgZGVmaW5lIERTSV9SWFBLVDFIX0RUX0xQX0NN RF9NQVNLCVZDNF9NQVNLKDcsIDApCj4gKyMgZGVmaW5lIERTSV9SWFBLVDFIX0RUX0xQX0NNRF9T SElGVAkwCj4gKwo+ICsjZGVmaW5lIERTSTBfUlhQS1QySAkJMHgxMCAvKiBBS0EgUlgyX1BLVEgg Ki8KPiArI2RlZmluZSBEU0kxX1JYUEtUMkgJCTB4MTgKPiArIyBkZWZpbmUgRFNJX1JYUEtUMUhf REVUX0VSUgkJQklUKDMwKQo+ICsjIGRlZmluZSBEU0lfUlhQS1QxSF9FQ0NfRVJSCQlCSVQoMjkp Cj4gKyMgZGVmaW5lIERTSV9SWFBLVDFIX0NPUl9FUlIJCUJJVCgyOCkKPiArIyBkZWZpbmUgRFNJ X1JYUEtUMUhfSU5DT01QX1BLVAkJQklUKDI1KQo+ICsjIGRlZmluZSBEU0lfUlhQS1QxSF9CQ19Q QVJBTV9NQVNLCVZDNF9NQVNLKDIzLCA4KQo+ICsjIGRlZmluZSBEU0lfUlhQS1QxSF9CQ19QQVJB TV9TSElGVAk4Cj4gKyMgZGVmaW5lIERTSV9SWFBLVDFIX0RUX01BU0sJCVZDNF9NQVNLKDcsIDAp Cj4gKyMgZGVmaW5lIERTSV9SWFBLVDFIX0RUX1NISUZUCQkwCj4gKwo+ICsjZGVmaW5lIERTSTBf VFhQS1RfQ01EX0ZJRk8JMHgxNCAvKiBBS0EgQ01EX0RBVEFGICovCj4gKyNkZWZpbmUgRFNJMV9U WFBLVF9DTURfRklGTwkweDFjCj4gKwo+ICsjZGVmaW5lIERTSTBfRElTUDBfQ1RSTAkJMHgxOAo+ ICsjIGRlZmluZSBEU0lfRElTUDBfUElYX0NMS19ESVZfTUFTSwlWQzRfTUFTSygyMSwgMTMpCj4g KyMgZGVmaW5lIERTSV9ESVNQMF9QSVhfQ0xLX0RJVl9TSElGVAkxMwo+ICsjIGRlZmluZSBEU0lf RElTUDBfTFBfU1RPUF9DVFJMX01BU0sJVkM0X01BU0soMTIsIDExKQo+ICsjIGRlZmluZSBEU0lf RElTUDBfTFBfU1RPUF9DVFJMX1NISUZUCTExCj4gKyMgZGVmaW5lIERTSV9ESVNQMF9MUF9TVE9Q X0RJU0FCTEUJMAo+ICsjIGRlZmluZSBEU0lfRElTUDBfTFBfU1RPUF9QRVJMSU5FCTEKPiArIyBk ZWZpbmUgRFNJX0RJU1AwX0xQX1NUT1BfUEVSRlJBTUUJMgo+ICsKPiArLyogVHJhbnNtaXQgUkdC IHBpeGVscyBhbmQgbnVsbCBwYWNrZXRzIG9ubHkgZHVyaW5nIEhBQ1RJVkUsIGluc3RlYWQKPiAr ICogb2YgZ29pbmcgdG8gTFAtU1RPUC4KPiArICovCj4gKyMgZGVmaW5lIERTSV9ESVNQX0hBQ1RJ VkVfTlVMTAkJQklUKDEwKQo+ICsvKiBUcmFuc21pdCBibGFua2luZyBwYWNrZXQgb25seSBkdXJp bmcgdmJsYW5rLCBpbnN0ZWFkIG9mIGFsbG93aW5nIExQLVNUT1AuICovCj4gKyMgZGVmaW5lIERT SV9ESVNQX1ZCTFBfQ1RSTAkJQklUKDkpCj4gKy8qIFRyYW5zbWl0IGJsYW5raW5nIHBhY2tldCBv bmx5IGR1cmluZyBIRlAsIGluc3RlYWQgb2YgYWxsb3dpbmcgTFAtU1RPUC4gKi8KPiArIyBkZWZp bmUgRFNJX0RJU1BfSEZQX0NUUkwJCUJJVCg4KQo+ICsvKiBUcmFuc21pdCBibGFua2luZyBwYWNr ZXQgb25seSBkdXJpbmcgSEJQLCBpbnN0ZWFkIG9mIGFsbG93aW5nIExQLVNUT1AuICovCj4gKyMg ZGVmaW5lIERTSV9ESVNQX0hCUF9DVFJMCQlCSVQoNykKPiArIyBkZWZpbmUgRFNJX0RJU1AwX0NI QU5ORUxfTUFTSwkJVkM0X01BU0soNiwgNSkKPiArIyBkZWZpbmUgRFNJX0RJU1AwX0NIQU5ORUxf U0hJRlQJNQo+ICsvKiBFbmFibGVzIGVuZCBldmVudHMgZm9yIEhTWU5DL1ZTWU5DLCBub3QganVz dCBzdGFydCBldmVudHMuICovCj4gKyMgZGVmaW5lIERTSV9ESVNQMF9TVF9FTkQJCUJJVCg0KQo+ ICsjIGRlZmluZSBEU0lfRElTUDBfUEZPUk1BVF9NQVNLCQlWQzRfTUFTSygzLCAyKQo+ICsjIGRl ZmluZSBEU0lfRElTUDBfUEZPUk1BVF9TSElGVAkyCj4gKyMgZGVmaW5lIERTSV9QRk9STUFUX1JH QjU2NQkJMAo+ICsjIGRlZmluZSBEU0lfUEZPUk1BVF9SR0I2NjZfUEFDS0VECTEKPiArIyBkZWZp bmUgRFNJX1BGT1JNQVRfUkdCNjY2CQkyCj4gKyMgZGVmaW5lIERTSV9QRk9STUFUX1JHQjg4OAkJ Mwo+ICsvKiBEZWZhdWx0IGlzIFZJREVPIG1vZGUuICovCj4gKyMgZGVmaW5lIERTSV9ESVNQMF9D T01NQU5EX01PREUJCUJJVCgxKQo+ICsjIGRlZmluZSBEU0lfRElTUDBfRU5BQkxFCQlCSVQoMCkK PiArCj4gKyNkZWZpbmUgRFNJMF9ESVNQMV9DVFJMCQkweDFjCj4gKyNkZWZpbmUgRFNJMV9ESVNQ MV9DVFJMCQkweDJjCj4gKy8qIEZvcm1hdCBvZiB0aGUgZGF0YSB3cml0dGVuIHRvIFRYUEtUX1BJ WF9GSUZPLiAqLwo+ICsjIGRlZmluZSBEU0lfRElTUDFfUEZPUk1BVF9NQVNLCQlWQzRfTUFTSygy LCAxKQo+ICsjIGRlZmluZSBEU0lfRElTUDFfUEZPUk1BVF9TSElGVAkxCj4gKyMgZGVmaW5lIERT SV9ESVNQMV9QRk9STUFUXzE2QklUCTAKPiArIyBkZWZpbmUgRFNJX0RJU1AxX1BGT1JNQVRfMjRC SVQJMQo+ICsjIGRlZmluZSBEU0lfRElTUDFfUEZPUk1BVF8zMkJJVF9MRQkyCj4gKyMgZGVmaW5l IERTSV9ESVNQMV9QRk9STUFUXzMyQklUX0JFCTMKPiArCj4gKy8qIERJU1AxIGlzIGFsd2F5cyBj b21tYW5kIG1vZGUuICovCj4gKyMgZGVmaW5lIERTSV9ESVNQMV9FTkFCTEUJCUJJVCgwKQo+ICsK PiArI2RlZmluZSBEU0kwX1RYUEtUX1BJWF9GSUZPCQkweDIwIC8qIEFLQSBQSVhfRklGTyAqLwo+ ICsKPiArI2RlZmluZSBEU0kwX0lOVF9TVEFUCQkweDI0Cj4gKyNkZWZpbmUgRFNJMF9JTlRfRU4J CTB4MjgKPiArIyBkZWZpbmUgRFNJMV9JTlRfUEhZX0QzX1VMUFMJCUJJVCgzMCkKPiArIyBkZWZp bmUgRFNJMV9JTlRfUEhZX0QzX1NUT1AJCUJJVCgyOSkKPiArIyBkZWZpbmUgRFNJMV9JTlRfUEhZ X0QyX1VMUFMJCUJJVCgyOCkKPiArIyBkZWZpbmUgRFNJMV9JTlRfUEhZX0QyX1NUT1AJCUJJVCgy NykKPiArIyBkZWZpbmUgRFNJMV9JTlRfUEhZX0QxX1VMUFMJCUJJVCgyNikKPiArIyBkZWZpbmUg RFNJMV9JTlRfUEhZX0QxX1NUT1AJCUJJVCgyNSkKPiArIyBkZWZpbmUgRFNJMV9JTlRfUEhZX0Qw X1VMUFMJCUJJVCgyNCkKPiArIyBkZWZpbmUgRFNJMV9JTlRfUEhZX0QwX1NUT1AJCUJJVCgyMykK PiArIyBkZWZpbmUgRFNJMV9JTlRfRklGT19FUlIJCUJJVCgyMikKPiArIyBkZWZpbmUgRFNJMV9J TlRfUEhZX0RJUl9SVEYJCUJJVCgyMSkKPiArIyBkZWZpbmUgRFNJMV9JTlRfUEhZX1JYTFBEVAkJ QklUKDIwKQo+ICsjIGRlZmluZSBEU0kxX0lOVF9QSFlfUlhUUklHCQlCSVQoMTkpCj4gKyMgZGVm aW5lIERTSTFfSU5UX1BIWV9EMF9MUERUCQlCSVQoMTgpCj4gKyMgZGVmaW5lIERTSTFfSU5UX1BI WV9ESVJfRlRSCQlCSVQoMTcpCj4gKwo+ICsvKiBTaWduYWxlZCB3aGVuIHRoZSBjbG9jayBsYW5l IGVudGVycyB0aGUgZ2l2ZW4gc3RhdGUuICovCj4gKyMgZGVmaW5lIERTSTFfSU5UX1BIWV9DTE9D S19VTFBTCUJJVCgxNikKPiArIyBkZWZpbmUgRFNJMV9JTlRfUEhZX0NMT0NLX0hTCQlCSVQoMTUp Cj4gKyMgZGVmaW5lIERTSTFfSU5UX1BIWV9DTE9DS19TVE9QCUJJVCgxNCkKPiArCj4gKy8qIFNp Z25hbGVkIG9uIHRpbWVvdXRzICovCj4gKyMgZGVmaW5lIERTSTFfSU5UX1BSX1RPCQkJQklUKDEz KQo+ICsjIGRlZmluZSBEU0kxX0lOVF9UQV9UTwkJCUJJVCgxMikKPiArIyBkZWZpbmUgRFNJMV9J TlRfTFBSWF9UTwkJQklUKDExKQo+ICsjIGRlZmluZSBEU0kxX0lOVF9IU1RYX1RPCQlCSVQoMTAp Cj4gKwo+ICsvKiBDb250ZW50aW9uIG9uIGEgbGluZSB3aGVuIHRyeWluZyB0byBkcml2ZSB0aGUg bGluZSBsb3cgKi8KPiArIyBkZWZpbmUgRFNJMV9JTlRfRVJSX0NPTlRfTFAxCQlCSVQoOSkKPiAr IyBkZWZpbmUgRFNJMV9JTlRfRVJSX0NPTlRfTFAwCQlCSVQoOCkKPiArCj4gKy8qIENvbnRyb2wg ZXJyb3I6IGluY29ycmVjdCBsaW5lIHN0YXRlIHNlcXVlbmNlIG9uIGRhdGEgbGFuZSAwLiAqLwo+ ICsjIGRlZmluZSBEU0kxX0lOVF9FUlJfQ09OVFJPTAkJQklUKDcpCj4gKy8qIExQRFQgc3luY2hy b25pemF0aW9uIGVycm9yIChiaXRzIHJlY2VpdmVkIG5vdCBhIG11bHRpcGxlIG9mIDguICovCj4g Kwo+ICsjIGRlZmluZSBEU0kxX0lOVF9FUlJfU1lOQ19FU0MJCUJJVCg2KQo+ICsvKiBTaWduYWxl ZCBhZnRlciByZWNlaXZpbmcgYW4gZXJyb3IgcGFja2V0IGZyb20gdGhlIGRpc3BsYXkgaW4KPiAr ICogcmVzcG9uc2UgdG8gYSByZWFkLgo+ICsgKi8KPiArIyBkZWZpbmUgRFNJMV9JTlRfUlhQS1Qy CQlCSVQoNSkKPiArLyogU2lnbmFsZWQgYWZ0ZXIgcmVjZWl2aW5nIGEgcGFja2V0LiAgVGhlIGhl YWRlciBhbmQgb3B0aW9uYWwgc2hvcnQKPiArICogcmVzcG9uc2Ugd2lsbCBiZSBpbiBSWFBLVDFI LCBhbmQgYSBsb25nIHJlc3BvbnNlIHdpbGwgYmUgaW4gdGhlCj4gKyAqIFJYUEtUX0ZJRk8uCj4g KyAqLwo+ICsjIGRlZmluZSBEU0kxX0lOVF9SWFBLVDEJCUJJVCg0KQo+ICsjIGRlZmluZSBEU0kx X0lOVF9UWFBLVDJfRE9ORQkJQklUKDMpCj4gKyMgZGVmaW5lIERTSTFfSU5UX1RYUEtUMl9FTkQJ CUJJVCgyKQo+ICsvKiBTaWduYWxlZCBhZnRlciBhbGwgcmVwZWF0cyBvZiBUWFBLVDEgYXJlIHRy YW5zZmVycmVkLiAqLwo+ICsjIGRlZmluZSBEU0kxX0lOVF9UWFBLVDFfRE9ORQkJQklUKDEpCj4g Ky8qIFNpZ25hbGVkIGFmdGVyIGVhY2ggVFhQS1QxIHJlcGVhdCBpcyBzY2hlZHVsZWQuICovCj4g KyMgZGVmaW5lIERTSTFfSU5UX1RYUEtUMV9FTkQJCUJJVCgwKQo+ICsKPiArI2RlZmluZSBEU0kx X0lOVEVSUlVQVFNfQUxXQVlTX0VOQUJMRUQJKERTSTFfSU5UX0VSUl9TWU5DX0VTQyB8IFwKPiAr CQkJCQkgRFNJMV9JTlRfRVJSX0NPTlRST0wgfAkgXAo+ICsJCQkJCSBEU0kxX0lOVF9FUlJfQ09O VF9MUDAgfCBcCj4gKwkJCQkJIERTSTFfSU5UX0VSUl9DT05UX0xQMSB8IFwKPiArCQkJCQkgRFNJ MV9JTlRfSFNUWF9UTyB8CSBcCj4gKwkJCQkJIERTSTFfSU5UX0xQUlhfVE8gfAkgXAo+ICsJCQkJ CSBEU0kxX0lOVF9UQV9UTyB8CSBcCj4gKwkJCQkJIERTSTFfSU5UX1BSX1RPKQo+ICsKPiArI2Rl ZmluZSBEU0kwX1NUQVQJCTB4MmMKPiArI2RlZmluZSBEU0kwX0hTVFhfVE9fQ05UCTB4MzAKPiAr I2RlZmluZSBEU0kwX0xQUlhfVE9fQ05UCTB4MzQKPiArI2RlZmluZSBEU0kwX1RBX1RPX0NOVAkJ MHgzOAo+ICsjZGVmaW5lIERTSTBfUFJfVE9fQ05UCQkweDNjCj4gKyNkZWZpbmUgRFNJMF9QSFlD CQkweDQwCj4gKyMgZGVmaW5lIERTSTFfUEhZQ19FU0NfQ0xLX0xQRFRfTUFTSwlWQzRfTUFTSygy NSwgMjApCj4gKyMgZGVmaW5lIERTSTFfUEhZQ19FU0NfQ0xLX0xQRFRfU0hJRlQJMjAKPiArIyBk ZWZpbmUgRFNJMV9QSFlDX0hTX0NMS19DT05USU5VT1VTCUJJVCgxOCkKPiArIyBkZWZpbmUgRFNJ MF9QSFlDX0VTQ19DTEtfTFBEVF9NQVNLCVZDNF9NQVNLKDE3LCAxMikKPiArIyBkZWZpbmUgRFNJ MF9QSFlDX0VTQ19DTEtfTFBEVF9TSElGVAkxMgo+ICsjIGRlZmluZSBEU0kxX1BIWUNfQ0xBTkVf VUxQUwkJQklUKDE3KQo+ICsjIGRlZmluZSBEU0kxX1BIWUNfQ0xBTkVfRU5BQkxFCQlCSVQoMTYp Cj4gKyMgZGVmaW5lIERTSV9QSFlDX0RMQU5FM19VTFBTCQlCSVQoMTMpCj4gKyMgZGVmaW5lIERT SV9QSFlDX0RMQU5FM19FTkFCTEUJCUJJVCgxMikKPiArIyBkZWZpbmUgRFNJMF9QSFlDX0hTX0NM S19DT05USU5VT1VTCUJJVCgxMCkKPiArIyBkZWZpbmUgRFNJMF9QSFlDX0NMQU5FX1VMUFMJCUJJ VCg5KQo+ICsjIGRlZmluZSBEU0lfUEhZQ19ETEFORTJfVUxQUwkJQklUKDkpCj4gKyMgZGVmaW5l IERTSTBfUEhZQ19DTEFORV9FTkFCTEUJCUJJVCg4KQo+ICsjIGRlZmluZSBEU0lfUEhZQ19ETEFO RTJfRU5BQkxFCQlCSVQoOCkKPiArIyBkZWZpbmUgRFNJX1BIWUNfRExBTkUxX1VMUFMJCUJJVCg1 KQo+ICsjIGRlZmluZSBEU0lfUEhZQ19ETEFORTFfRU5BQkxFCQlCSVQoNCkKPiArIyBkZWZpbmUg RFNJX1BIWUNfRExBTkUwX0ZPUkNFX1NUT1AJQklUKDIpCj4gKyMgZGVmaW5lIERTSV9QSFlDX0RM QU5FMF9VTFBTCQlCSVQoMSkKPiArIyBkZWZpbmUgRFNJX1BIWUNfRExBTkUwX0VOQUJMRQkJQklU KDApCj4gKwo+ICsjZGVmaW5lIERTSTBfSFNfQ0xUMAkJMHg0NAo+ICsjZGVmaW5lIERTSTBfSFNf Q0xUMQkJMHg0OAo+ICsjZGVmaW5lIERTSTBfSFNfQ0xUMgkJMHg0Ywo+ICsjZGVmaW5lIERTSTBf SFNfRExUMwkJMHg1MAo+ICsjZGVmaW5lIERTSTBfSFNfRExUNAkJMHg1NAo+ICsjZGVmaW5lIERT STBfSFNfRExUNQkJMHg1OAo+ICsjZGVmaW5lIERTSTBfSFNfRExUNgkJMHg1Ywo+ICsjZGVmaW5l IERTSTBfSFNfRExUNwkJMHg2MAo+ICsKPiArI2RlZmluZSBEU0kwX1BIWV9BRkVDMAkJMHg2NAo+ ICsjIGRlZmluZSBEU0kwX1BIWV9BRkVDMF9ERFIyQ0xLX0VOCQlCSVQoMjYpCj4gKyMgZGVmaW5l IERTSTBfUEhZX0FGRUMwX0REUkNMS19FTgkJQklUKDI1KQo+ICsjIGRlZmluZSBEU0kwX1BIWV9B RkVDMF9MQVRDSF9VTFBTCQlCSVQoMjQpCj4gKyMgZGVmaW5lIERTSTFfUEhZX0FGRUMwX0lEUl9E TEFORTNfTUFTSwkJVkM0X01BU0soMzEsIDI5KQo+ICsjIGRlZmluZSBEU0kxX1BIWV9BRkVDMF9J RFJfRExBTkUzX1NISUZUCTI5Cj4gKyMgZGVmaW5lIERTSTFfUEhZX0FGRUMwX0lEUl9ETEFORTJf TUFTSwkJVkM0X01BU0soMjgsIDI2KQo+ICsjIGRlZmluZSBEU0kxX1BIWV9BRkVDMF9JRFJfRExB TkUyX1NISUZUCTI2Cj4gKyMgZGVmaW5lIERTSTFfUEhZX0FGRUMwX0lEUl9ETEFORTFfTUFTSwkJ VkM0X01BU0soMjcsIDIzKQo+ICsjIGRlZmluZSBEU0kxX1BIWV9BRkVDMF9JRFJfRExBTkUxX1NI SUZUCTIzCj4gKyMgZGVmaW5lIERTSTFfUEhZX0FGRUMwX0lEUl9ETEFORTBfTUFTSwkJVkM0X01B U0soMjIsIDIwKQo+ICsjIGRlZmluZSBEU0kxX1BIWV9BRkVDMF9JRFJfRExBTkUwX1NISUZUCTIw Cj4gKyMgZGVmaW5lIERTSTFfUEhZX0FGRUMwX0lEUl9DTEFORV9NQVNLCQlWQzRfTUFTSygxOSwg MTcpCj4gKyMgZGVmaW5lIERTSTFfUEhZX0FGRUMwX0lEUl9DTEFORV9TSElGVAkJMTcKPiArIyBk ZWZpbmUgRFNJMF9QSFlfQUZFQzBfQUNUUkxfRExBTkUxX01BU0sJVkM0X01BU0soMjMsIDIwKQo+ ICsjIGRlZmluZSBEU0kwX1BIWV9BRkVDMF9BQ1RSTF9ETEFORTFfU0hJRlQJMjAKPiArIyBkZWZp bmUgRFNJMF9QSFlfQUZFQzBfQUNUUkxfRExBTkUwX01BU0sJVkM0X01BU0soMTksIDE2KQo+ICsj IGRlZmluZSBEU0kwX1BIWV9BRkVDMF9BQ1RSTF9ETEFORTBfU0hJRlQJMTYKPiArIyBkZWZpbmUg RFNJMF9QSFlfQUZFQzBfQUNUUkxfQ0xBTkVfTUFTSwlWQzRfTUFTSygxNSwgMTIpCj4gKyMgZGVm aW5lIERTSTBfUEhZX0FGRUMwX0FDVFJMX0NMQU5FX1NISUZUCTEyCj4gKyMgZGVmaW5lIERTSTFf UEhZX0FGRUMwX0REUjJDTEtfRU4JCUJJVCgxNikKPiArIyBkZWZpbmUgRFNJMV9QSFlfQUZFQzBf RERSQ0xLX0VOCQlCSVQoMTUpCj4gKyMgZGVmaW5lIERTSTFfUEhZX0FGRUMwX0xBVENIX1VMUFMJ CUJJVCgxNCkKPiArIyBkZWZpbmUgRFNJMV9QSFlfQUZFQzBfUkVTRVQJCQlCSVQoMTMpCj4gKyMg ZGVmaW5lIERTSTFfUEhZX0FGRUMwX1BECQkJQklUKDEyKQo+ICsjIGRlZmluZSBEU0kwX1BIWV9B RkVDMF9SRVNFVAkJCUJJVCgxMSkKPiArIyBkZWZpbmUgRFNJMV9QSFlfQUZFQzBfUERfQkcJCQlC SVQoMTEpCj4gKyMgZGVmaW5lIERTSTBfUEhZX0FGRUMwX1BECQkJQklUKDEwKQo+ICsjIGRlZmlu ZSBEU0kxX1BIWV9BRkVDMF9QRF9ETEFORTMJCUJJVCgxMCkKPiArIyBkZWZpbmUgRFNJMF9QSFlf QUZFQzBfUERfQkcJCQlCSVQoOSkKPiArIyBkZWZpbmUgRFNJMV9QSFlfQUZFQzBfUERfRExBTkUy CQlCSVQoOSkKPiArIyBkZWZpbmUgRFNJMF9QSFlfQUZFQzBfUERfRExBTkUxCQlCSVQoOCkKPiAr IyBkZWZpbmUgRFNJMV9QSFlfQUZFQzBfUERfRExBTkUxCQlCSVQoOCkKPiArIyBkZWZpbmUgRFNJ X1BIWV9BRkVDMF9QVEFUQURKX01BU0sJCVZDNF9NQVNLKDcsIDQpCj4gKyMgZGVmaW5lIERTSV9Q SFlfQUZFQzBfUFRBVEFESl9TSElGVAkJNAo+ICsjIGRlZmluZSBEU0lfUEhZX0FGRUMwX0NUQVRB REpfTUFTSwkJVkM0X01BU0soMywgMCkKPiArIyBkZWZpbmUgRFNJX1BIWV9BRkVDMF9DVEFUQURK X1NISUZUCQkwCj4gKwo+ICsjZGVmaW5lIERTSTBfUEhZX0FGRUMxCQkweDY4Cj4gKyMgZGVmaW5l IERTSTBfUEhZX0FGRUMxX0lEUl9ETEFORTFfTUFTSwkJVkM0X01BU0soMTAsIDgpCj4gKyMgZGVm aW5lIERTSTBfUEhZX0FGRUMxX0lEUl9ETEFORTFfU0hJRlQJOAo+ICsjIGRlZmluZSBEU0kwX1BI WV9BRkVDMV9JRFJfRExBTkUwX01BU0sJCVZDNF9NQVNLKDYsIDQpCj4gKyMgZGVmaW5lIERTSTBf UEhZX0FGRUMxX0lEUl9ETEFORTBfU0hJRlQJNAo+ICsjIGRlZmluZSBEU0kwX1BIWV9BRkVDMV9J RFJfQ0xBTkVfTUFTSwkJVkM0X01BU0soMiwgMCkKPiArIyBkZWZpbmUgRFNJMF9QSFlfQUZFQzFf SURSX0NMQU5FX1NISUZUCQkwCj4gKwo+ICsjZGVmaW5lIERTSTBfVFNUX1NFTAkJMHg2Ywo+ICsj ZGVmaW5lIERTSTBfVFNUX01PTgkJMHg3MAo+ICsjZGVmaW5lIERTSTBfSUQJCQkweDc0Cj4gKyMg ZGVmaW5lIERTSV9JRF9WQUxVRQkJMHgwMDY0NzM2OQo+ICsKPiArI2RlZmluZSBEU0kxX0NUUkwJ CTB4MDAKPiArIyBkZWZpbmUgRFNJX0NUUkxfSFNfQ0xLQ19NQVNLCQlWQzRfTUFTSygxNSwgMTQp Cj4gKyMgZGVmaW5lIERTSV9DVFJMX0hTX0NMS0NfU0hJRlQJCTE0Cj4gKyMgZGVmaW5lIERTSV9D VFJMX0hTX0NMS0NfQllURQkJMAo+ICsjIGRlZmluZSBEU0lfQ1RSTF9IU19DTEtDX0REUjIJCTEK PiArIyBkZWZpbmUgRFNJX0NUUkxfSFNfQ0xLQ19ERFIJCTIKPiArCj4gKyMgZGVmaW5lIERTSV9D VFJMX1JYX0xQRFRfRU9UX0RJU0FCTEUJQklUKDEzKQo+ICsjIGRlZmluZSBEU0lfQ1RSTF9MUERU X0VPVF9ESVNBQkxFCUJJVCgxMikKPiArIyBkZWZpbmUgRFNJX0NUUkxfSFNEVF9FT1RfRElTQUJM RQlCSVQoMTEpCj4gKyMgZGVmaW5lIERTSV9DVFJMX1NPRlRfUkVTRVRfQ0ZHCUJJVCgxMCkKPiAr IyBkZWZpbmUgRFNJX0NUUkxfQ0FMX0JZVEUJCUJJVCg5KQo+ICsjIGRlZmluZSBEU0lfQ1RSTF9J TlZfQllURQkJQklUKDgpCj4gKyMgZGVmaW5lIERTSV9DVFJMX0NMUl9MREYJCUJJVCg3KQo+ICsj IGRlZmluZSBEU0kwX0NUUkxfQ0xSX1BCQ0YJCUJJVCg2KQo+ICsjIGRlZmluZSBEU0kxX0NUUkxf Q0xSX1JYRgkJQklUKDYpCj4gKyMgZGVmaW5lIERTSTBfQ1RSTF9DTFJfQ1BCQ0YJCUJJVCg1KQo+ ICsjIGRlZmluZSBEU0kxX0NUUkxfQ0xSX1BERgkJQklUKDUpCj4gKyMgZGVmaW5lIERTSTBfQ1RS TF9DTFJfUERGCQlCSVQoNCkKPiArIyBkZWZpbmUgRFNJMV9DVFJMX0NMUl9DREYJCUJJVCg0KQo+ ICsjIGRlZmluZSBEU0kwX0NUUkxfQ0xSX0NERgkJQklUKDMpCj4gKyMgZGVmaW5lIERTSTBfQ1RS TF9DVFJMMgkJQklUKDIpCj4gKyMgZGVmaW5lIERTSTFfQ1RSTF9ESVNBQkxFX0RJU1BfQ1JDQwlC SVQoMikKPiArIyBkZWZpbmUgRFNJMF9DVFJMX0NUUkwxCQlCSVQoMSkKPiArIyBkZWZpbmUgRFNJ MV9DVFJMX0RJU0FCTEVfRElTUF9FQ0NDCUJJVCgxKQo+ICsjIGRlZmluZSBEU0kwX0NUUkxfQ1RS TDAJCUJJVCgwKQo+ICsjIGRlZmluZSBEU0kxX0NUUkxfRU4JCQlCSVQoMCkKPiArIyBkZWZpbmUg RFNJMF9DVFJMX1JFU0VUX0ZJRk9TCQkoRFNJX0NUUkxfQ0xSX0xERiB8IFwKPiArCQkJCQkgRFNJ MF9DVFJMX0NMUl9QQkNGIHwgXAo+ICsJCQkJCSBEU0kwX0NUUkxfQ0xSX0NQQkNGIHwJXAo+ICsJ CQkJCSBEU0kwX0NUUkxfQ0xSX1BERiB8IFwKPiArCQkJCQkgRFNJMF9DVFJMX0NMUl9DREYpCj4g KyMgZGVmaW5lIERTSTFfQ1RSTF9SRVNFVF9GSUZPUwkJKERTSV9DVFJMX0NMUl9MREYgfCBcCj4g KwkJCQkJIERTSTFfQ1RSTF9DTFJfUlhGIHwgXAo+ICsJCQkJCSBEU0kxX0NUUkxfQ0xSX1BERiB8 IFwKPiArCQkJCQkgRFNJMV9DVFJMX0NMUl9DREYpCj4gKwo+ICsjZGVmaW5lIERTSTFfVFhQS1Qy QwkJMHgwYwo+ICsjZGVmaW5lIERTSTFfVFhQS1QySAkJMHgxMAo+ICsjZGVmaW5lIERTSTFfVFhQ S1RfUElYX0ZJRk8JMHgyMAo+ICsjZGVmaW5lIERTSTFfUlhQS1RfRklGTwkJMHgyNAo+ICsjZGVm aW5lIERTSTFfRElTUDBfQ1RSTAkJMHgyOAo+ICsjZGVmaW5lIERTSTFfSU5UX1NUQVQJCTB4MzAK PiArI2RlZmluZSBEU0kxX0lOVF9FTgkJMHgzNAo+ICsvKiBTdGF0ZSByZXBvcnRpbmcgYml0cy4g IFRoZXNlIG1vc3RseSBiZWhhdmUgbGlrZSBJTlRfU1RBVCwgd2hlcmUKPiArICogd3JpdGluZyBh IDEgY2xlYXJzIHRoZSBiaXQuCj4gKyAqLwo+ICsjZGVmaW5lIERTSTFfU1RBVAkJMHgzOAo+ICsj IGRlZmluZSBEU0kxX1NUQVRfUEhZX0QzX1VMUFMJCUJJVCgzMSkKPiArIyBkZWZpbmUgRFNJMV9T VEFUX1BIWV9EM19TVE9QCQlCSVQoMzApCj4gKyMgZGVmaW5lIERTSTFfU1RBVF9QSFlfRDJfVUxQ UwkJQklUKDI5KQo+ICsjIGRlZmluZSBEU0kxX1NUQVRfUEhZX0QyX1NUT1AJCUJJVCgyOCkKPiAr IyBkZWZpbmUgRFNJMV9TVEFUX1BIWV9EMV9VTFBTCQlCSVQoMjcpCj4gKyMgZGVmaW5lIERTSTFf U1RBVF9QSFlfRDFfU1RPUAkJQklUKDI2KQo+ICsjIGRlZmluZSBEU0kxX1NUQVRfUEhZX0QwX1VM UFMJCUJJVCgyNSkKPiArIyBkZWZpbmUgRFNJMV9TVEFUX1BIWV9EMF9TVE9QCQlCSVQoMjQpCj4g KyMgZGVmaW5lIERTSTFfU1RBVF9GSUZPX0VSUgkJQklUKDIzKQo+ICsjIGRlZmluZSBEU0kxX1NU QVRfUEhZX1JYTFBEVAkJQklUKDIyKQo+ICsjIGRlZmluZSBEU0kxX1NUQVRfUEhZX1JYVFJJRwkJ QklUKDIxKQo+ICsjIGRlZmluZSBEU0kxX1NUQVRfUEhZX0QwX0xQRFQJCUJJVCgyMCkKPiArLyog U2V0IHdoZW4gaW4gZm9yd2FyZCBkaXJlY3Rpb24gKi8KPiArIyBkZWZpbmUgRFNJMV9TVEFUX1BI WV9ESVIJCUJJVCgxOSkKPiArIyBkZWZpbmUgRFNJMV9TVEFUX1BIWV9DTE9DS19VTFBTCUJJVCgx OCkKPiArIyBkZWZpbmUgRFNJMV9TVEFUX1BIWV9DTE9DS19IUwkJQklUKDE3KQo+ICsjIGRlZmlu ZSBEU0kxX1NUQVRfUEhZX0NMT0NLX1NUT1AJQklUKDE2KQo+ICsjIGRlZmluZSBEU0kxX1NUQVRf UFJfVE8JCUJJVCgxNSkKPiArIyBkZWZpbmUgRFNJMV9TVEFUX1RBX1RPCQlCSVQoMTQpCj4gKyMg ZGVmaW5lIERTSTFfU1RBVF9MUFJYX1RPCQlCSVQoMTMpCj4gKyMgZGVmaW5lIERTSTFfU1RBVF9I U1RYX1RPCQlCSVQoMTIpCj4gKyMgZGVmaW5lIERTSTFfU1RBVF9FUlJfQ09OVF9MUDEJCUJJVCgx MSkKPiArIyBkZWZpbmUgRFNJMV9TVEFUX0VSUl9DT05UX0xQMAkJQklUKDEwKQo+ICsjIGRlZmlu ZSBEU0kxX1NUQVRfRVJSX0NPTlRST0wJCUJJVCg5KQo+ICsjIGRlZmluZSBEU0kxX1NUQVRfRVJS X1NZTkNfRVNDCQlCSVQoOCkKPiArIyBkZWZpbmUgRFNJMV9TVEFUX1JYUEtUMgkJQklUKDcpCj4g KyMgZGVmaW5lIERTSTFfU1RBVF9SWFBLVDEJCUJJVCg2KQo+ICsjIGRlZmluZSBEU0kxX1NUQVRf VFhQS1QyX0JVU1kJCUJJVCg1KQo+ICsjIGRlZmluZSBEU0kxX1NUQVRfVFhQS1QyX0RPTkUJCUJJ VCg0KQo+ICsjIGRlZmluZSBEU0kxX1NUQVRfVFhQS1QyX0VORAkJQklUKDMpCj4gKyMgZGVmaW5l IERTSTFfU1RBVF9UWFBLVDFfQlVTWQkJQklUKDIpCj4gKyMgZGVmaW5lIERTSTFfU1RBVF9UWFBL VDFfRE9ORQkJQklUKDEpCj4gKyMgZGVmaW5lIERTSTFfU1RBVF9UWFBLVDFfRU5ECQlCSVQoMCkK PiArCj4gKyNkZWZpbmUgRFNJMV9IU1RYX1RPX0NOVAkweDNjCj4gKyNkZWZpbmUgRFNJMV9MUFJY X1RPX0NOVAkweDQwCj4gKyNkZWZpbmUgRFNJMV9UQV9UT19DTlQJCTB4NDQKPiArI2RlZmluZSBE U0kxX1BSX1RPX0NOVAkJMHg0OAo+ICsjZGVmaW5lIERTSTFfUEhZQwkJMHg0Ywo+ICsKPiArI2Rl ZmluZSBEU0kxX0hTX0NMVDAJCTB4NTAKPiArIyBkZWZpbmUgRFNJX0hTX0NMVDBfQ1pFUk9fTUFT SwkJVkM0X01BU0soMjYsIDE4KQo+ICsjIGRlZmluZSBEU0lfSFNfQ0xUMF9DWkVST19TSElGVAkx OAo+ICsjIGRlZmluZSBEU0lfSFNfQ0xUMF9DUFJFX01BU0sJCVZDNF9NQVNLKDE3LCA5KQo+ICsj IGRlZmluZSBEU0lfSFNfQ0xUMF9DUFJFX1NISUZUCQk5Cj4gKyMgZGVmaW5lIERTSV9IU19DTFQw X0NQUkVQX01BU0sJCVZDNF9NQVNLKDgsIDApCj4gKyMgZGVmaW5lIERTSV9IU19DTFQwX0NQUkVQ X1NISUZUCTAKPiArCj4gKyNkZWZpbmUgRFNJMV9IU19DTFQxCQkweDU0Cj4gKyMgZGVmaW5lIERT SV9IU19DTFQxX0NUUkFJTF9NQVNLCVZDNF9NQVNLKDE3LCA5KQo+ICsjIGRlZmluZSBEU0lfSFNf Q0xUMV9DVFJBSUxfU0hJRlQJOQo+ICsjIGRlZmluZSBEU0lfSFNfQ0xUMV9DUE9TVF9NQVNLCQlW QzRfTUFTSyg4LCAwKQo+ICsjIGRlZmluZSBEU0lfSFNfQ0xUMV9DUE9TVF9TSElGVAkwCj4gKwo+ ICsjZGVmaW5lIERTSTFfSFNfQ0xUMgkJMHg1OAo+ICsjIGRlZmluZSBEU0lfSFNfQ0xUMl9XVVBf TUFTSwkJVkM0X01BU0soMjMsIDApCj4gKyMgZGVmaW5lIERTSV9IU19DTFQyX1dVUF9TSElGVAkJ MAo+ICsKPiArI2RlZmluZSBEU0kxX0hTX0RMVDMJCTB4NWMKPiArIyBkZWZpbmUgRFNJX0hTX0RM VDNfRVhJVF9NQVNLCQlWQzRfTUFTSygyNiwgMTgpCj4gKyMgZGVmaW5lIERTSV9IU19ETFQzX0VY SVRfU0hJRlQJCTE4Cj4gKyMgZGVmaW5lIERTSV9IU19ETFQzX1pFUk9fTUFTSwkJVkM0X01BU0so MTcsIDkpCj4gKyMgZGVmaW5lIERTSV9IU19ETFQzX1pFUk9fU0hJRlQJCTkKPiArIyBkZWZpbmUg RFNJX0hTX0RMVDNfUFJFX01BU0sJCVZDNF9NQVNLKDgsIDApCj4gKyMgZGVmaW5lIERTSV9IU19E TFQzX1BSRV9TSElGVAkJMAo+ICsKPiArI2RlZmluZSBEU0kxX0hTX0RMVDQJCTB4NjAKPiArIyBk ZWZpbmUgRFNJX0hTX0RMVDRfQU5MQVRfTUFTSwkJVkM0X01BU0soMjIsIDE4KQo+ICsjIGRlZmlu ZSBEU0lfSFNfRExUNF9BTkxBVF9TSElGVAkxOAo+ICsjIGRlZmluZSBEU0lfSFNfRExUNF9UUkFJ TF9NQVNLCQlWQzRfTUFTSygxNywgOSkKPiArIyBkZWZpbmUgRFNJX0hTX0RMVDRfVFJBSUxfU0hJ RlQJOQo+ICsjIGRlZmluZSBEU0lfSFNfRExUNF9MUFhfTUFTSwkJVkM0X01BU0soOCwgMCkKPiAr IyBkZWZpbmUgRFNJX0hTX0RMVDRfTFBYX1NISUZUCQkwCj4gKwo+ICsjZGVmaW5lIERTSTFfSFNf RExUNQkJMHg2NAo+ICsjIGRlZmluZSBEU0lfSFNfRExUNV9JTklUX01BU0sJCVZDNF9NQVNLKDIz LCAwKQo+ICsjIGRlZmluZSBEU0lfSFNfRExUNV9JTklUX1NISUZUCQkwCj4gKwo+ICsjZGVmaW5l IERTSTFfSFNfRExUNgkJMHg2OAo+ICsjIGRlZmluZSBEU0lfSFNfRExUNl9UQV9HRVRfTUFTSwlW QzRfTUFTSygzMSwgMjQpCj4gKyMgZGVmaW5lIERTSV9IU19ETFQ2X1RBX0dFVF9TSElGVAkyNAo+ ICsjIGRlZmluZSBEU0lfSFNfRExUNl9UQV9TVVJFX01BU0sJVkM0X01BU0soMjMsIDE2KQo+ICsj IGRlZmluZSBEU0lfSFNfRExUNl9UQV9TVVJFX1NISUZUCTE2Cj4gKyMgZGVmaW5lIERTSV9IU19E TFQ2X1RBX0dPX01BU0sJCVZDNF9NQVNLKDE1LCA4KQo+ICsjIGRlZmluZSBEU0lfSFNfRExUNl9U QV9HT19TSElGVAk4Cj4gKyMgZGVmaW5lIERTSV9IU19ETFQ2X0xQX0xQWF9NQVNLCVZDNF9NQVNL KDcsIDApCj4gKyMgZGVmaW5lIERTSV9IU19ETFQ2X0xQX0xQWF9TSElGVAkwCj4gKwo+ICsjZGVm aW5lIERTSTFfSFNfRExUNwkJMHg2Ywo+ICsjIGRlZmluZSBEU0lfSFNfRExUN19MUF9XVVBfTUFT SwlWQzRfTUFTSygyMywgMCkKPiArIyBkZWZpbmUgRFNJX0hTX0RMVDdfTFBfV1VQX1NISUZUCTAK PiArCj4gKyNkZWZpbmUgRFNJMV9QSFlfQUZFQzAJCTB4NzAKPiArCj4gKyNkZWZpbmUgRFNJMV9Q SFlfQUZFQzEJCTB4NzQKPiArIyBkZWZpbmUgRFNJMV9QSFlfQUZFQzFfQUNUUkxfRExBTkUzX01B U0sJVkM0X01BU0soMTksIDE2KQo+ICsjIGRlZmluZSBEU0kxX1BIWV9BRkVDMV9BQ1RSTF9ETEFO RTNfU0hJRlQJMTYKPiArIyBkZWZpbmUgRFNJMV9QSFlfQUZFQzFfQUNUUkxfRExBTkUyX01BU0sJ VkM0X01BU0soMTUsIDEyKQo+ICsjIGRlZmluZSBEU0kxX1BIWV9BRkVDMV9BQ1RSTF9ETEFORTJf U0hJRlQJMTIKPiArIyBkZWZpbmUgRFNJMV9QSFlfQUZFQzFfQUNUUkxfRExBTkUxX01BU0sJVkM0 X01BU0soMTEsIDgpCj4gKyMgZGVmaW5lIERTSTFfUEhZX0FGRUMxX0FDVFJMX0RMQU5FMV9TSElG VAk4Cj4gKyMgZGVmaW5lIERTSTFfUEhZX0FGRUMxX0FDVFJMX0RMQU5FMF9NQVNLCVZDNF9NQVNL KDcsIDQpCj4gKyMgZGVmaW5lIERTSTFfUEhZX0FGRUMxX0FDVFJMX0RMQU5FMF9TSElGVAk0Cj4g KyMgZGVmaW5lIERTSTFfUEhZX0FGRUMxX0FDVFJMX0NMQU5FX01BU0sJVkM0X01BU0soMywgMCkK PiArIyBkZWZpbmUgRFNJMV9QSFlfQUZFQzFfQUNUUkxfQ0xBTkVfU0hJRlQJMAo+ICsKPiArI2Rl ZmluZSBEU0kxX1RTVF9TRUwJCTB4NzgKPiArI2RlZmluZSBEU0kxX1RTVF9NT04JCTB4N2MKPiAr I2RlZmluZSBEU0kxX1BIWV9UU1QxCQkweDgwCj4gKyNkZWZpbmUgRFNJMV9QSFlfVFNUMgkJMHg4 NAo+ICsjZGVmaW5lIERTSTFfUEhZX0ZJRk9fU1RBVAkweDg4Cj4gKy8qIEFjdHVhbGx5LCBhbGwg cmVnaXN0ZXJzIGluIHRoZSByYW5nZSB0aGF0IGFyZW4ndCBvdGhlcndpc2UgY2xhaW1lZAo+ICsg KiB3aWxsIHJldHVybiB0aGUgSUQuCj4gKyAqLwo+ICsjZGVmaW5lIERTSTFfSUQJCQkweDhjCj4g Kwo+ICsvKiBHZW5lcmFsIERTSSBoYXJkd2FyZSBzdGF0ZS4gKi8KPiArc3RydWN0IHZjNF9kc2kg ewo+ICsJc3RydWN0IHBsYXRmb3JtX2RldmljZSAqcGRldjsKPiArCj4gKwlzdHJ1Y3QgbWlwaV9k c2lfaG9zdCBkc2lfaG9zdDsKPiArCXN0cnVjdCBkcm1fZW5jb2RlciAqZW5jb2RlcjsKPiArCXN0 cnVjdCBkcm1fY29ubmVjdG9yICpjb25uZWN0b3I7Cj4gKwlzdHJ1Y3QgZHJtX3BhbmVsICpwYW5l bDsKPiArCj4gKwl2b2lkIF9faW9tZW0gKnJlZ3M7Cj4gKwo+ICsJc3RydWN0IGRtYV9jaGFuICpy ZWdfZG1hX2NoYW47Cj4gKwlkbWFfYWRkcl90IHJlZ19kbWFfcGFkZHI7Cj4gKwl1MzIgKnJlZ19k bWFfbWVtOwo+ICsJZG1hX2FkZHJfdCByZWdfcGFkZHI7Cj4gKwo+ICsJLyogV2hldGhlciB3ZSdy ZSBvbiBiY20yODM1J3MgRFNJMCBvciBEU0kxLiAqLwo+ICsJaW50IHBvcnQ7Cj4gKwo+ICsJLyog RFNJIGNoYW5uZWwgZm9yIHRoZSBwYW5lbCB3ZSdyZSBjb25uZWN0ZWQgdG8uICovCj4gKwl1MzIg Y2hhbm5lbDsKPiArCXUzMiBsYW5lczsKPiArCWVudW0gbWlwaV9kc2lfcGl4ZWxfZm9ybWF0IGZv cm1hdDsKPiArCXUzMiBtb2RlX2ZsYWdzOwo+ICsKPiArCS8qIElucHV0IGNsb2NrIGZyb20gQ1BS TUFOIHRvIHRoZSBkaWdpdGFsIFBIWSwgZm9yIHRoZSBEU0kKPiArCSAqIGVzY2FwZSBjbG9jay4K PiArCSAqLwo+ICsJc3RydWN0IGNsayAqZXNjYXBlX2Nsb2NrOwo+ICsKPiArCS8qIElucHV0IGNs b2NrIHRvIHRoZSBhbmFsb2cgUEhZLCB1c2VkIHRvIGdlbmVyYXRlIHRoZSBEU0kgYml0Cj4gKwkg KiBjbG9jay4KPiArCSAqLwo+ICsJc3RydWN0IGNsayAqcGxsX3BoeV9jbG9jazsKPiArCj4gKwkv KiBIUyBDbG9ja3MgZ2VuZXJhdGVkIHdpdGhpbiB0aGUgRFNJIGFuYWxvZyBQSFkuICovCj4gKwlz dHJ1Y3QgY2xrX2ZpeGVkX2ZhY3RvciBwaHlfY2xvY2tzWzNdOwo+ICsKPiArCXN0cnVjdCBjbGtf b25lY2VsbF9kYXRhIGNsa19vbmVjZWxsOwo+ICsKPiArCS8qIFBpeGVsIGNsb2NrIG91dHB1dCB0 byB0aGUgcGl4ZWx2YWx2ZSwgZ2VuZXJhdGVkIGZyb20gdGhlIEhTCj4gKwkgKiBjbG9jay4KPiAr CSAqLwo+ICsJc3RydWN0IGNsayAqcGl4ZWxfY2xvY2s7Cj4gKwo+ICsJc3RydWN0IGNvbXBsZXRp b24geGZlcl9jb21wbGV0aW9uOwo+ICsJaW50IHhmZXJfcmVzdWx0Owo+ICt9Owo+ICsKPiArI2Rl ZmluZSBob3N0X3RvX2RzaShob3N0KSBjb250YWluZXJfb2YoaG9zdCwgc3RydWN0IHZjNF9kc2ks IGRzaV9ob3N0KQo+ICsKPiArc3RhdGljIGlubGluZSB2b2lkCj4gK2RzaV9kbWFfd29ya2Fyb3Vu ZF93cml0ZShzdHJ1Y3QgdmM0X2RzaSAqZHNpLCB1MzIgb2Zmc2V0LCB1MzIgdmFsKQo+ICt7Cj4g KwlzdHJ1Y3QgZG1hX2NoYW4gKmNoYW4gPSBkc2ktPnJlZ19kbWFfY2hhbjsKPiArCXN0cnVjdCBk bWFfYXN5bmNfdHhfZGVzY3JpcHRvciAqdHg7Cj4gKwlkbWFfY29va2llX3QgY29va2llOwo+ICsJ aW50IHJldDsKPiArCj4gKwkvKiBEU0kwIHNob3VsZCBiZSBhYmxlIHRvIHdyaXRlIG5vcm1hbGx5 LiAqLwo+ICsJaWYgKCFjaGFuKSB7Cj4gKwkJd3JpdGVsKHZhbCwgZHNpLT5yZWdzICsgb2Zmc2V0 KTsKPiArCQlyZXR1cm47Cj4gKwl9Cj4gKwo+ICsJKmRzaS0+cmVnX2RtYV9tZW0gPSB2YWw7Cj4g Kwo+ICsJdHggPSBjaGFuLT5kZXZpY2UtPmRldmljZV9wcmVwX2RtYV9tZW1jcHkoY2hhbiwKPiAr CQkJCQkJICBkc2ktPnJlZ19wYWRkciArIG9mZnNldCwKPiArCQkJCQkJICBkc2ktPnJlZ19kbWFf cGFkZHIsCj4gKwkJCQkJCSAgNCwgMCk7Cj4gKwlpZiAoIXR4KSB7Cj4gKwkJRFJNX0VSUk9SKCJG YWlsZWQgdG8gc2V0IHVwIERNQSByZWdpc3RlciB3cml0ZVxuIik7Cj4gKwkJcmV0dXJuOwo+ICsJ fQo+ICsKPiArCWNvb2tpZSA9IHR4LT50eF9zdWJtaXQodHgpOwo+ICsJcmV0ID0gZG1hX3N1Ym1p dF9lcnJvcihjb29raWUpOwo+ICsJaWYgKHJldCkgewo+ICsJCURSTV9FUlJPUigiRmFpbGVkIHRv IHN1Ym1pdCBETUE6ICVkXG4iLCByZXQpOwo+ICsJCXJldHVybjsKPiArCX0KPiArCXJldCA9IGRt YV9zeW5jX3dhaXQoY2hhbiwgY29va2llKTsKPiArCWlmIChyZXQpCj4gKwkJRFJNX0VSUk9SKCJG YWlsZWQgdG8gd2FpdCBmb3IgRE1BOiAlZFxuIiwgcmV0KTsKPiArfQo+ICsKPiArI2RlZmluZSBE U0lfUkVBRChvZmZzZXQpIHJlYWRsKGRzaS0+cmVncyArIChvZmZzZXQpKQo+ICsjZGVmaW5lIERT SV9XUklURShvZmZzZXQsIHZhbCkgZHNpX2RtYV93b3JrYXJvdW5kX3dyaXRlKGRzaSwgb2Zmc2V0 LCB2YWwpCj4gKyNkZWZpbmUgRFNJX1BPUlRfUkVBRChvZmZzZXQpIFwKPiArCURTSV9SRUFEKGRz aS0+cG9ydCA/IERTSTFfIyNvZmZzZXQgOiBEU0kwXyMjb2Zmc2V0KQo+ICsjZGVmaW5lIERTSV9Q T1JUX1dSSVRFKG9mZnNldCwgdmFsKSBcCj4gKwlEU0lfV1JJVEUoZHNpLT5wb3J0ID8gRFNJMV8j I29mZnNldCA6IERTSTBfIyNvZmZzZXQsIHZhbCkKPiArI2RlZmluZSBEU0lfUE9SVF9CSVQoYml0 KSAoZHNpLT5wb3J0ID8gRFNJMV8jI2JpdCA6IERTSTBfIyNiaXQpCj4gKwo+ICsvKiBWQzQgRFNJ IGVuY29kZXIgS01TIHN0cnVjdCAqLwo+ICtzdHJ1Y3QgdmM0X2RzaV9lbmNvZGVyIHsKPiArCXN0 cnVjdCB2YzRfZW5jb2RlciBiYXNlOwo+ICsJc3RydWN0IHZjNF9kc2kgKmRzaTsKPiArfTsKPiAr Cj4gK3N0YXRpYyBpbmxpbmUgc3RydWN0IHZjNF9kc2lfZW5jb2RlciAqCj4gK3RvX3ZjNF9kc2lf ZW5jb2RlcihzdHJ1Y3QgZHJtX2VuY29kZXIgKmVuY29kZXIpCj4gK3sKPiArCXJldHVybiBjb250 YWluZXJfb2YoZW5jb2Rlciwgc3RydWN0IHZjNF9kc2lfZW5jb2RlciwgYmFzZS5iYXNlKTsKPiAr fQo+ICsKPiArLyogVkM0IERTSSBjb25uZWN0b3IgS01TIHN0cnVjdCAqLwo+ICtzdHJ1Y3QgdmM0 X2RzaV9jb25uZWN0b3Igewo+ICsJc3RydWN0IGRybV9jb25uZWN0b3IgYmFzZTsKPiArCXN0cnVj dCB2YzRfZHNpICpkc2k7Cj4gK307Cj4gKwo+ICtzdGF0aWMgaW5saW5lIHN0cnVjdCB2YzRfZHNp X2Nvbm5lY3RvciAqCj4gK3RvX3ZjNF9kc2lfY29ubmVjdG9yKHN0cnVjdCBkcm1fY29ubmVjdG9y ICpjb25uZWN0b3IpCj4gK3sKPiArCXJldHVybiBjb250YWluZXJfb2YoY29ubmVjdG9yLCBzdHJ1 Y3QgdmM0X2RzaV9jb25uZWN0b3IsIGJhc2UpOwo+ICt9Cj4gKwo+ICsjZGVmaW5lIERTSV9SRUco cmVnKSB7IHJlZywgI3JlZyB9Cj4gK3N0YXRpYyBjb25zdCBzdHJ1Y3Qgewo+ICsJdTMyIHJlZzsK PiArCWNvbnN0IGNoYXIgKm5hbWU7Cj4gK30gZHNpMF9yZWdzW10gPSB7Cj4gKwlEU0lfUkVHKERT STBfQ1RSTCksCj4gKwlEU0lfUkVHKERTSTBfU1RBVCksCj4gKwlEU0lfUkVHKERTSTBfSFNUWF9U T19DTlQpLAo+ICsJRFNJX1JFRyhEU0kwX0xQUlhfVE9fQ05UKSwKPiArCURTSV9SRUcoRFNJMF9U QV9UT19DTlQpLAo+ICsJRFNJX1JFRyhEU0kwX1BSX1RPX0NOVCksCj4gKwlEU0lfUkVHKERTSTBf RElTUDBfQ1RSTCksCj4gKwlEU0lfUkVHKERTSTBfRElTUDFfQ1RSTCksCj4gKwlEU0lfUkVHKERT STBfSU5UX1NUQVQpLAo+ICsJRFNJX1JFRyhEU0kwX0lOVF9FTiksCj4gKwlEU0lfUkVHKERTSTBf UEhZQyksCj4gKwlEU0lfUkVHKERTSTBfSFNfQ0xUMCksCj4gKwlEU0lfUkVHKERTSTBfSFNfQ0xU MSksCj4gKwlEU0lfUkVHKERTSTBfSFNfQ0xUMiksCj4gKwlEU0lfUkVHKERTSTBfSFNfRExUMyks Cj4gKwlEU0lfUkVHKERTSTBfSFNfRExUNCksCj4gKwlEU0lfUkVHKERTSTBfSFNfRExUNSksCj4g KwlEU0lfUkVHKERTSTBfSFNfRExUNiksCj4gKwlEU0lfUkVHKERTSTBfSFNfRExUNyksCj4gKwlE U0lfUkVHKERTSTBfUEhZX0FGRUMwKSwKPiArCURTSV9SRUcoRFNJMF9QSFlfQUZFQzEpLAo+ICsJ RFNJX1JFRyhEU0kwX0lEKSwKPiArfTsKPiArCj4gK3N0YXRpYyBjb25zdCBzdHJ1Y3Qgewo+ICsJ dTMyIHJlZzsKPiArCWNvbnN0IGNoYXIgKm5hbWU7Cj4gK30gZHNpMV9yZWdzW10gPSB7Cj4gKwlE U0lfUkVHKERTSTFfQ1RSTCksCj4gKwlEU0lfUkVHKERTSTFfU1RBVCksCj4gKwlEU0lfUkVHKERT STFfSFNUWF9UT19DTlQpLAo+ICsJRFNJX1JFRyhEU0kxX0xQUlhfVE9fQ05UKSwKPiArCURTSV9S RUcoRFNJMV9UQV9UT19DTlQpLAo+ICsJRFNJX1JFRyhEU0kxX1BSX1RPX0NOVCksCj4gKwlEU0lf UkVHKERTSTFfRElTUDBfQ1RSTCksCj4gKwlEU0lfUkVHKERTSTFfRElTUDFfQ1RSTCksCj4gKwlE U0lfUkVHKERTSTFfSU5UX1NUQVQpLAo+ICsJRFNJX1JFRyhEU0kxX0lOVF9FTiksCj4gKwlEU0lf UkVHKERTSTFfUEhZQyksCj4gKwlEU0lfUkVHKERTSTFfSFNfQ0xUMCksCj4gKwlEU0lfUkVHKERT STFfSFNfQ0xUMSksCj4gKwlEU0lfUkVHKERTSTFfSFNfQ0xUMiksCj4gKwlEU0lfUkVHKERTSTFf SFNfRExUMyksCj4gKwlEU0lfUkVHKERTSTFfSFNfRExUNCksCj4gKwlEU0lfUkVHKERTSTFfSFNf RExUNSksCj4gKwlEU0lfUkVHKERTSTFfSFNfRExUNiksCj4gKwlEU0lfUkVHKERTSTFfSFNfRExU NyksCj4gKwlEU0lfUkVHKERTSTFfUEhZX0FGRUMwKSwKPiArCURTSV9SRUcoRFNJMV9QSFlfQUZF QzEpLAo+ICsJRFNJX1JFRyhEU0kxX0lEKSwKPiArfTsKPiArCj4gK3N0YXRpYyB2b2lkIHZjNF9k c2lfZHVtcF9yZWdzKHN0cnVjdCB2YzRfZHNpICpkc2kpCj4gK3sKPiArCWludCBpOwo+ICsKPiAr CWlmIChkc2ktPnBvcnQgPT0gMCkgewo+ICsJCWZvciAoaSA9IDA7IGkgPCBBUlJBWV9TSVpFKGRz aTBfcmVncyk7IGkrKykgewo+ICsJCQlEUk1fSU5GTygiMHglMDR4ICglcyk6IDB4JTA4eFxuIiwK PiArCQkJCSBkc2kwX3JlZ3NbaV0ucmVnLCBkc2kwX3JlZ3NbaV0ubmFtZSwKPiArCQkJCSBEU0lf UkVBRChkc2kwX3JlZ3NbaV0ucmVnKSk7Cj4gKwkJfQo+ICsJfSBlbHNlIHsKPiArCQlmb3IgKGkg PSAwOyBpIDwgQVJSQVlfU0laRShkc2kxX3JlZ3MpOyBpKyspIHsKPiArCQkJRFJNX0lORk8oIjB4 JTA0eCAoJXMpOiAweCUwOHhcbiIsCj4gKwkJCQkgZHNpMV9yZWdzW2ldLnJlZywgZHNpMV9yZWdz W2ldLm5hbWUsCj4gKwkJCQkgRFNJX1JFQUQoZHNpMV9yZWdzW2ldLnJlZykpOwo+ICsJCX0KPiAr CX0KPiArfQo+ICsKPiArI2lmZGVmIENPTkZJR19ERUJVR19GUwo+ICtpbnQgdmM0X2RzaV9kZWJ1 Z2ZzX3JlZ3Moc3RydWN0IHNlcV9maWxlICptLCB2b2lkICp1bnVzZWQpCj4gK3sKPiArCXN0cnVj dCBkcm1faW5mb19ub2RlICpub2RlID0gKHN0cnVjdCBkcm1faW5mb19ub2RlICopbS0+cHJpdmF0 ZTsKPiArCXN0cnVjdCBkcm1fZGV2aWNlICpkcm0gPSBub2RlLT5taW5vci0+ZGV2Owo+ICsJc3Ry dWN0IHZjNF9kZXYgKnZjNCA9IHRvX3ZjNF9kZXYoZHJtKTsKPiArCWludCBkc2lfaW5kZXggPSAo dWludHB0cl90KW5vZGUtPmluZm9fZW50LT5kYXRhOwo+ICsJc3RydWN0IHZjNF9kc2kgKmRzaSA9 IChkc2lfaW5kZXggPT0gMSA/IHZjNC0+ZHNpMSA6IE5VTEwpOwo+ICsJaW50IGk7Cj4gKwo+ICsJ aWYgKCFkc2kpCj4gKwkJcmV0dXJuIDA7Cj4gKwo+ICsJaWYgKGRzaS0+cG9ydCA9PSAwKSB7Cj4g KwkJZm9yIChpID0gMDsgaSA8IEFSUkFZX1NJWkUoZHNpMF9yZWdzKTsgaSsrKSB7Cj4gKwkJCXNl cV9wcmludGYobSwgIjB4JTA0eCAoJXMpOiAweCUwOHhcbiIsCj4gKwkJCQkgICBkc2kwX3JlZ3Nb aV0ucmVnLCBkc2kwX3JlZ3NbaV0ubmFtZSwKPiArCQkJCSAgIERTSV9SRUFEKGRzaTBfcmVnc1tp XS5yZWcpKTsKPiArCQl9Cj4gKwl9IGVsc2Ugewo+ICsJCWZvciAoaSA9IDA7IGkgPCBBUlJBWV9T SVpFKGRzaTFfcmVncyk7IGkrKykgewo+ICsJCQlzZXFfcHJpbnRmKG0sICIweCUwNHggKCVzKTog MHglMDh4XG4iLAo+ICsJCQkJICAgZHNpMV9yZWdzW2ldLnJlZywgZHNpMV9yZWdzW2ldLm5hbWUs Cj4gKwkJCQkgICBEU0lfUkVBRChkc2kxX3JlZ3NbaV0ucmVnKSk7Cj4gKwkJfQo+ICsJfQo+ICsK PiArCXJldHVybiAwOwo+ICt9Cj4gKyNlbmRpZgo+ICsKPiArc3RhdGljIGVudW0gZHJtX2Nvbm5l Y3Rvcl9zdGF0dXMKPiArdmM0X2RzaV9jb25uZWN0b3JfZGV0ZWN0KHN0cnVjdCBkcm1fY29ubmVj dG9yICpjb25uZWN0b3IsIGJvb2wgZm9yY2UpCj4gK3sKPiArCXN0cnVjdCB2YzRfZHNpX2Nvbm5l Y3RvciAqdmM0X2Nvbm5lY3RvciA9Cj4gKwkJdG9fdmM0X2RzaV9jb25uZWN0b3IoY29ubmVjdG9y KTsKPiArCXN0cnVjdCB2YzRfZHNpICpkc2kgPSB2YzRfY29ubmVjdG9yLT5kc2k7Cj4gKwo+ICsJ aWYgKGRzaS0+cGFuZWwpCj4gKwkJcmV0dXJuIGNvbm5lY3Rvcl9zdGF0dXNfY29ubmVjdGVkOwo+ ICsJZWxzZQo+ICsJCXJldHVybiBjb25uZWN0b3Jfc3RhdHVzX2Rpc2Nvbm5lY3RlZDsKPiArfQo+ ICsKPiArc3RhdGljIHZvaWQgdmM0X2RzaV9jb25uZWN0b3JfZGVzdHJveShzdHJ1Y3QgZHJtX2Nv bm5lY3RvciAqY29ubmVjdG9yKQo+ICt7Cj4gKwlkcm1fY29ubmVjdG9yX3VucmVnaXN0ZXIoY29u bmVjdG9yKTsKPiArCWRybV9jb25uZWN0b3JfY2xlYW51cChjb25uZWN0b3IpOwo+ICt9Cj4gKwo+ ICtzdGF0aWMgaW50IHZjNF9kc2lfY29ubmVjdG9yX2dldF9tb2RlcyhzdHJ1Y3QgZHJtX2Nvbm5l Y3RvciAqY29ubmVjdG9yKQo+ICt7Cj4gKwlzdHJ1Y3QgdmM0X2RzaV9jb25uZWN0b3IgKnZjNF9j b25uZWN0b3IgPQo+ICsJCXRvX3ZjNF9kc2lfY29ubmVjdG9yKGNvbm5lY3Rvcik7Cj4gKwlzdHJ1 Y3QgdmM0X2RzaSAqZHNpID0gdmM0X2Nvbm5lY3Rvci0+ZHNpOwo+ICsKPiArCWlmIChkc2ktPnBh bmVsKQo+ICsJCXJldHVybiBkcm1fcGFuZWxfZ2V0X21vZGVzKGRzaS0+cGFuZWwpOwo+ICsKPiAr CXJldHVybiAwOwo+ICt9CgpJJ20gc3RpbGwgaG9waW5nIHRoYXQgc29tZXdoZW4gc29tZW9uZSBh ZGRzIGEgZHJtX3BhbmVsICogcG9pbnRlciB0bwpkcm1fY29ubmVjdG9yIGFuZCB3cml0ZXMgdGhl IGdsdWUgZnVuY3Rpb25zIGluIGEgaGVscGVyIGxpYnJhcnkgc28gd2UKY291bGQgZ2FyYmFnZS1j b2xsZWN0IGFsbCBvdXIgY29waWVzIG9mIHRoZSBzYW1lIHN0dWZmIGltcGxlbWVudGluZwotPmRl dGVjdCBhbmQgLT5nZXRfbW9kZXMgLi4uCgo+ICsKPiArc3RhdGljIGNvbnN0IHN0cnVjdCBkcm1f Y29ubmVjdG9yX2Z1bmNzIHZjNF9kc2lfY29ubmVjdG9yX2Z1bmNzID0gewo+ICsJLmRwbXMgPSBk cm1fYXRvbWljX2hlbHBlcl9jb25uZWN0b3JfZHBtcywKPiArCS5kZXRlY3QgPSB2YzRfZHNpX2Nv bm5lY3Rvcl9kZXRlY3QsCj4gKwkuZmlsbF9tb2RlcyA9IGRybV9oZWxwZXJfcHJvYmVfc2luZ2xl X2Nvbm5lY3Rvcl9tb2RlcywKPiArCS5kZXN0cm95ID0gdmM0X2RzaV9jb25uZWN0b3JfZGVzdHJv eSwKPiArCS5yZXNldCA9IGRybV9hdG9taWNfaGVscGVyX2Nvbm5lY3Rvcl9yZXNldCwKPiArCS5h dG9taWNfZHVwbGljYXRlX3N0YXRlID0gZHJtX2F0b21pY19oZWxwZXJfY29ubmVjdG9yX2R1cGxp Y2F0ZV9zdGF0ZSwKPiArCS5hdG9taWNfZGVzdHJveV9zdGF0ZSA9IGRybV9hdG9taWNfaGVscGVy X2Nvbm5lY3Rvcl9kZXN0cm95X3N0YXRlLAo+ICt9Owo+ICsKPiArc3RhdGljIGNvbnN0IHN0cnVj dCBkcm1fY29ubmVjdG9yX2hlbHBlcl9mdW5jcyB2YzRfZHNpX2Nvbm5lY3Rvcl9oZWxwZXJfZnVu Y3MgPSB7Cj4gKwkuZ2V0X21vZGVzID0gdmM0X2RzaV9jb25uZWN0b3JfZ2V0X21vZGVzLAo+ICt9 Owo+ICsKPiArc3RhdGljIHN0cnVjdCBkcm1fY29ubmVjdG9yICp2YzRfZHNpX2Nvbm5lY3Rvcl9p bml0KHN0cnVjdCBkcm1fZGV2aWNlICpkZXYsCj4gKwkJCQkJCSAgICBzdHJ1Y3QgdmM0X2RzaSAq ZHNpKQo+ICt7Cj4gKwlzdHJ1Y3QgZHJtX2Nvbm5lY3RvciAqY29ubmVjdG9yID0gTlVMTDsKPiAr CXN0cnVjdCB2YzRfZHNpX2Nvbm5lY3RvciAqZHNpX2Nvbm5lY3RvcjsKPiArCWludCByZXQgPSAw Owo+ICsKPiArCWRzaV9jb25uZWN0b3IgPSBkZXZtX2t6YWxsb2MoZGV2LT5kZXYsIHNpemVvZigq ZHNpX2Nvbm5lY3RvciksCj4gKwkJCQkgICAgIEdGUF9LRVJORUwpOwo+ICsJaWYgKCFkc2lfY29u bmVjdG9yKSB7Cj4gKwkJcmV0ID0gLUVOT01FTTsKPiArCQlnb3RvIGZhaWw7Cj4gKwl9Cj4gKwlj b25uZWN0b3IgPSAmZHNpX2Nvbm5lY3Rvci0+YmFzZTsKPiArCj4gKwlkc2lfY29ubmVjdG9yLT5k c2kgPSBkc2k7Cj4gKwo+ICsJZHJtX2Nvbm5lY3Rvcl9pbml0KGRldiwgY29ubmVjdG9yLCAmdmM0 X2RzaV9jb25uZWN0b3JfZnVuY3MsCj4gKwkJCSAgIERSTV9NT0RFX0NPTk5FQ1RPUl9EU0kpOwo+ ICsJZHJtX2Nvbm5lY3Rvcl9oZWxwZXJfYWRkKGNvbm5lY3RvciwgJnZjNF9kc2lfY29ubmVjdG9y X2hlbHBlcl9mdW5jcyk7Cj4gKwo+ICsJY29ubmVjdG9yLT5wb2xsZWQgPSAwOwo+ICsJY29ubmVj dG9yLT5pbnRlcmxhY2VfYWxsb3dlZCA9IDA7Cj4gKwljb25uZWN0b3ItPmRvdWJsZXNjYW5fYWxs b3dlZCA9IDA7Cj4gKwo+ICsJZHJtX21vZGVfY29ubmVjdG9yX2F0dGFjaF9lbmNvZGVyKGNvbm5l Y3RvciwgZHNpLT5lbmNvZGVyKTsKPiArCj4gKwlyZXR1cm4gY29ubmVjdG9yOwo+ICsKPiArZmFp bDoKPiArCWlmIChjb25uZWN0b3IpCj4gKwkJdmM0X2RzaV9jb25uZWN0b3JfZGVzdHJveShjb25u ZWN0b3IpOwo+ICsKPiArCXJldHVybiBFUlJfUFRSKHJldCk7Cj4gK30KPiArCj4gK3N0YXRpYyB2 b2lkIHZjNF9kc2lfZW5jb2Rlcl9kZXN0cm95KHN0cnVjdCBkcm1fZW5jb2RlciAqZW5jb2RlcikK PiArewo+ICsJZHJtX2VuY29kZXJfY2xlYW51cChlbmNvZGVyKTsKPiArfQo+ICsKPiArc3RhdGlj IGNvbnN0IHN0cnVjdCBkcm1fZW5jb2Rlcl9mdW5jcyB2YzRfZHNpX2VuY29kZXJfZnVuY3MgPSB7 Cj4gKwkuZGVzdHJveSA9IHZjNF9kc2lfZW5jb2Rlcl9kZXN0cm95LAo+ICt9Owo+ICsKPiArc3Rh dGljIHZvaWQgdmM0X2RzaV9sYXRjaF91bHBzKHN0cnVjdCB2YzRfZHNpICpkc2ksIGJvb2wgbGF0 Y2gpCj4gK3sKPiArCXUzMiBhZmVjMCA9IERTSV9QT1JUX1JFQUQoUEhZX0FGRUMwKTsKPiArCj4g KwlpZiAobGF0Y2gpCj4gKwkJYWZlYzAgfD0gRFNJX1BPUlRfQklUKFBIWV9BRkVDMF9MQVRDSF9V TFBTKTsKPiArCWVsc2UKPiArCQlhZmVjMCAmPSB+RFNJX1BPUlRfQklUKFBIWV9BRkVDMF9MQVRD SF9VTFBTKTsKPiArCj4gKwlEU0lfUE9SVF9XUklURShQSFlfQUZFQzAsIGFmZWMwKTsKPiArfQo+ ICsKPiArLyogRW50ZXJzIG9yIGV4aXRzIFVsdHJhIExvdyBQb3dlciBTdGF0ZS4gKi8KPiArc3Rh dGljIHZvaWQgdmM0X2RzaV91bHBzKHN0cnVjdCB2YzRfZHNpICpkc2ksIGJvb2wgdWxwcykKPiAr ewo+ICsJYm9vbCBjb250aW51b3VzID0gZHNpLT5tb2RlX2ZsYWdzICYgTUlQSV9EU0lfQ0xPQ0tf Tk9OX0NPTlRJTlVPVVM7Cj4gKwl1MzIgcGh5Y191bHBzID0gKChjb250aW51b3VzID8gRFNJX1BP UlRfQklUKFBIWUNfQ0xBTkVfVUxQUykgOiAwKSB8Cj4gKwkJCSBEU0lfUEhZQ19ETEFORTBfVUxQ UyB8Cj4gKwkJCSAoZHNpLT5sYW5lcyA+IDEgPyBEU0lfUEhZQ19ETEFORTFfVUxQUyA6IDApIHwK PiArCQkJIChkc2ktPmxhbmVzID4gMiA/IERTSV9QSFlDX0RMQU5FMl9VTFBTIDogMCkgfAo+ICsJ CQkgKGRzaS0+bGFuZXMgPiAzID8gRFNJX1BIWUNfRExBTkUzX1VMUFMgOiAwKSk7Cj4gKwl1MzIg c3RhdF91bHBzID0gKChjb250aW51b3VzID8gRFNJMV9TVEFUX1BIWV9DTE9DS19VTFBTIDogMCkg fAo+ICsJCQkgRFNJMV9TVEFUX1BIWV9EMF9VTFBTIHwKPiArCQkJIChkc2ktPmxhbmVzID4gMSA/ IERTSTFfU1RBVF9QSFlfRDFfVUxQUyA6IDApIHwKPiArCQkJIChkc2ktPmxhbmVzID4gMiA/IERT STFfU1RBVF9QSFlfRDJfVUxQUyA6IDApIHwKPiArCQkJIChkc2ktPmxhbmVzID4gMyA/IERTSTFf U1RBVF9QSFlfRDNfVUxQUyA6IDApKTsKPiArCXUzMiBzdGF0X3N0b3AgPSAoKGNvbnRpbnVvdXMg PyBEU0kxX1NUQVRfUEhZX0NMT0NLX1NUT1AgOiAwKSB8Cj4gKwkJCSBEU0kxX1NUQVRfUEhZX0Qw X1NUT1AgfAo+ICsJCQkgKGRzaS0+bGFuZXMgPiAxID8gRFNJMV9TVEFUX1BIWV9EMV9TVE9QIDog MCkgfAo+ICsJCQkgKGRzaS0+bGFuZXMgPiAyID8gRFNJMV9TVEFUX1BIWV9EMl9TVE9QIDogMCkg fAo+ICsJCQkgKGRzaS0+bGFuZXMgPiAzID8gRFNJMV9TVEFUX1BIWV9EM19TVE9QIDogMCkpOwo+ ICsJaW50IHJldDsKPiArCj4gKwlEU0lfUE9SVF9XUklURShTVEFULCBzdGF0X3VscHMpOwo+ICsJ RFNJX1BPUlRfV1JJVEUoUEhZQywgRFNJX1BPUlRfUkVBRChQSFlDKSB8IHBoeWNfdWxwcyk7Cj4g KwlyZXQgPSB3YWl0X2ZvcigoRFNJX1BPUlRfUkVBRChTVEFUKSAmIHN0YXRfdWxwcykgPT0gc3Rh dF91bHBzLCAyMDApOwo+ICsJaWYgKHJldCkgewo+ICsJCWRldl93YXJuKCZkc2ktPnBkZXYtPmRl diwKPiArCQkJICJUaW1lb3V0IHdhaXRpbmcgZm9yIERTSSBVTFBTIGVudHJ5OiBTVEFUIDB4JTA4 eCIsCj4gKwkJCSBEU0lfUE9SVF9SRUFEKFNUQVQpKTsKPiArCQlEU0lfUE9SVF9XUklURShQSFlD LCBEU0lfUE9SVF9SRUFEKFBIWUMpICYgfnBoeWNfdWxwcyk7Cj4gKwkJdmM0X2RzaV9sYXRjaF91 bHBzKGRzaSwgZmFsc2UpOwo+ICsJCXJldHVybjsKPiArCX0KPiArCj4gKwkvKiBUaGUgRFNJIG1v ZHVsZSBjYW4ndCBiZSBkaXNhYmxlZCB3aGlsZSB0aGUgbW9kdWxlIGlzCj4gKwkgKiBnZW5lcmF0 aW5nIFVMUFMgc3RhdGUuICBTbywgdG8gYmUgYWJsZSB0byBkaXNhYmxlIHRoZQo+ICsJICogbW9k dWxlLCB3ZSBoYXZlIHRoZSBBRkUgbGF0Y2ggdGhlIFVMUFMgc3RhdGUgYW5kIGNvbnRpbnVlCj4g KwkgKiBvbiB0byBoYXZpbmcgdGhlIG1vZHVsZSBlbnRlciBTVE9QLgo+ICsJICovCj4gKwl2YzRf ZHNpX2xhdGNoX3VscHMoZHNpLCB1bHBzKTsKPiArCj4gKwlEU0lfUE9SVF9XUklURShTVEFULCBz dGF0X3N0b3ApOwo+ICsJRFNJX1BPUlRfV1JJVEUoUEhZQywgRFNJX1BPUlRfUkVBRChQSFlDKSAm IH5waHljX3VscHMpOwo+ICsJcmV0ID0gd2FpdF9mb3IoKERTSV9QT1JUX1JFQUQoU1RBVCkgJiBz dGF0X3N0b3ApID09IHN0YXRfc3RvcCwgMjAwKTsKPiArCWlmIChyZXQpIHsKPiArCQlkZXZfd2Fy bigmZHNpLT5wZGV2LT5kZXYsCj4gKwkJCSAiVGltZW91dCB3YWl0aW5nIGZvciBEU0kgU1RPUCBl bnRyeTogU1RBVCAweCUwOHgiLAo+ICsJCQkgRFNJX1BPUlRfUkVBRChTVEFUKSk7Cj4gKwkJRFNJ X1BPUlRfV1JJVEUoUEhZQywgRFNJX1BPUlRfUkVBRChQSFlDKSAmIH5waHljX3VscHMpOwo+ICsJ CXJldHVybjsKPiArCX0KPiArfQo+ICsKPiArc3RhdGljIHUzMgo+ICtkc2lfaHNfdGltaW5nKHUz MiB1aV9ucywgdTMyIG5zLCB1MzIgdWkpCj4gK3sKPiArCS8qIFRoZSBIUyB0aW1pbmdzIGhhdmUg dG8gYmUgcm91bmRlZCB1cCB0byBhIG11bHRpcGxlIG9mIDgKPiArCSAqIGJlY2F1c2Ugd2UncmUg dXNpbmcgdGhlIGJ5dGUgY2xvY2suCj4gKwkgKi8KPiArCXJldHVybiByb3VuZHVwKHVpICsgRElW X1JPVU5EX1VQKG5zLCB1aV9ucyksIDgpOwo+ICt9Cj4gKwo+ICsvKiBFU0MgYWx3YXlzIHJ1bnMg YXQgMTAwTWh6LiAqLwo+ICsjZGVmaW5lIEVTQ19USU1FX05TIDEwCj4gKwo+ICtzdGF0aWMgdTMy Cj4gK2RzaV9lc2NfdGltaW5nKHUzMiBucykKPiArewo+ICsJcmV0dXJuIERJVl9ST1VORF9VUChu cywgRVNDX1RJTUVfTlMpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgdm9pZCB2YzRfZHNpX2VuY29kZXJf ZGlzYWJsZShzdHJ1Y3QgZHJtX2VuY29kZXIgKmVuY29kZXIpCj4gK3sKPiArCXN0cnVjdCB2YzRf ZHNpX2VuY29kZXIgKnZjNF9lbmNvZGVyID0gdG9fdmM0X2RzaV9lbmNvZGVyKGVuY29kZXIpOwo+ ICsJc3RydWN0IHZjNF9kc2kgKmRzaSA9IHZjNF9lbmNvZGVyLT5kc2k7Cj4gKwlzdHJ1Y3QgZGV2 aWNlICpkZXYgPSAmZHNpLT5wZGV2LT5kZXY7Cj4gKwo+ICsJZHJtX3BhbmVsX2Rpc2FibGUoZHNp LT5wYW5lbCk7Cj4gKwo+ICsJdmM0X2RzaV91bHBzKGRzaSwgdHJ1ZSk7Cj4gKwo+ICsJZHJtX3Bh bmVsX3VucHJlcGFyZShkc2ktPnBhbmVsKTsKPiArCj4gKwljbGtfZGlzYWJsZV91bnByZXBhcmUo ZHNpLT5wbGxfcGh5X2Nsb2NrKTsKPiArCWNsa19kaXNhYmxlX3VucHJlcGFyZShkc2ktPmVzY2Fw ZV9jbG9jayk7Cj4gKwljbGtfZGlzYWJsZV91bnByZXBhcmUoZHNpLT5waXhlbF9jbG9jayk7Cj4g Kwo+ICsJcG1fcnVudGltZV9wdXQoZGV2KTsKPiArfQo+ICsKPiArc3RhdGljIHZvaWQgdmM0X2Rz aV9lbmNvZGVyX2VuYWJsZShzdHJ1Y3QgZHJtX2VuY29kZXIgKmVuY29kZXIpCj4gK3sKPiArCXN0 cnVjdCBkcm1fZGlzcGxheV9tb2RlICptb2RlID0gJmVuY29kZXItPmNydGMtPm1vZGU7Cj4gKwlz dHJ1Y3QgdmM0X2RzaV9lbmNvZGVyICp2YzRfZW5jb2RlciA9IHRvX3ZjNF9kc2lfZW5jb2Rlcihl bmNvZGVyKTsKPiArCXN0cnVjdCB2YzRfZHNpICpkc2kgPSB2YzRfZW5jb2Rlci0+ZHNpOwo+ICsJ c3RydWN0IGRldmljZSAqZGV2ID0gJmRzaS0+cGRldi0+ZGV2Owo+ICsJdTMyIGZvcm1hdCA9IDAs IGRpdmlkZXIgPSAwOwo+ICsJYm9vbCBkZWJ1Z19kdW1wX3JlZ3MgPSBmYWxzZTsKPiArCXVuc2ln bmVkIGxvbmcgaHNfY2xvY2s7Cj4gKwl1MzIgdWlfbnM7Cj4gKwkvKiBNaW5pbXVtIExQIHN0YXRl IGR1cmF0aW9uIGluIGVzY2FwZSBjbG9jayBjeWNsZXMuICovCj4gKwl1MzIgbHB4ID0gZHNpX2Vz Y190aW1pbmcoNjApOwo+ICsJdW5zaWduZWQgbG9uZyBwaXhlbF9jbG9ja19oeiA9IG1vZGUtPmNs b2NrICogMTAwMDsKPiArCXVuc2lnbmVkIGxvbmcgZHNpcF9jbG9jazsKPiArCXVuc2lnbmVkIGxv bmcgcGh5X2Nsb2NrOwo+ICsJaW50IHJldDsKPiArCj4gKwlyZXQgPSBwbV9ydW50aW1lX2dldF9z eW5jKGRldik7Cj4gKwlpZiAocmV0KSB7Cj4gKwkJRFJNX0VSUk9SKCJGYWlsZWQgdG8gcnVudGlt ZSBQTSBlbmFibGUgb24gRFNJJWRcbiIsIGRzaS0+cG9ydCk7Cj4gKwkJcmV0dXJuOwo+ICsJfQo+ ICsKPiArCXJldCA9IGRybV9wYW5lbF9wcmVwYXJlKGRzaS0+cGFuZWwpOwo+ICsJaWYgKHJldCkg ewo+ICsJCURSTV9FUlJPUigiUGFuZWwgZmFpbGVkIHRvIHByZXBhcmVcbiIpOwo+ICsJCXJldHVy bjsKPiArCX0KPiArCj4gKwlpZiAoZGVidWdfZHVtcF9yZWdzKSB7Cj4gKwkJRFJNX0lORk8oIkRT SSByZWdzIGJlZm9yZTpcbiIpOwo+ICsJCXZjNF9kc2lfZHVtcF9yZWdzKGRzaSk7Cj4gKwl9Cj4g Kwo+ICsJc3dpdGNoIChkc2ktPmZvcm1hdCkgewo+ICsJY2FzZSBNSVBJX0RTSV9GTVRfUkdCODg4 Ogo+ICsJCWZvcm1hdCA9IERTSV9QRk9STUFUX1JHQjg4ODsKPiArCQlkaXZpZGVyID0gMjQgLyBk c2ktPmxhbmVzOwo+ICsJCWJyZWFrOwo+ICsJY2FzZSBNSVBJX0RTSV9GTVRfUkdCNjY2Ogo+ICsJ CWZvcm1hdCA9IERTSV9QRk9STUFUX1JHQjY2NjsKPiArCQlkaXZpZGVyID0gMjQgLyBkc2ktPmxh bmVzOwo+ICsJCWJyZWFrOwo+ICsJY2FzZSBNSVBJX0RTSV9GTVRfUkdCNjY2X1BBQ0tFRDoKPiAr CQlmb3JtYXQgPSBEU0lfUEZPUk1BVF9SR0I2NjZfUEFDS0VEOwo+ICsJCWRpdmlkZXIgPSAxOCAv IGRzaS0+bGFuZXM7Cj4gKwkJYnJlYWs7Cj4gKwljYXNlIE1JUElfRFNJX0ZNVF9SR0I1NjU6Cj4g KwkJZm9ybWF0ID0gRFNJX1BGT1JNQVRfUkdCNTY1Owo+ICsJCWRpdmlkZXIgPSAxNiAvIGRzaS0+ bGFuZXM7Cj4gKwkJYnJlYWs7Cj4gKwl9Cj4gKwo+ICsJcGh5X2Nsb2NrID0gcGl4ZWxfY2xvY2tf aHogKiBkaXZpZGVyOwo+ICsJcmV0ID0gY2xrX3NldF9yYXRlKGRzaS0+cGxsX3BoeV9jbG9jaywg cGh5X2Nsb2NrKTsKPiArCWlmIChyZXQpIHsKPiArCQlkZXZfZXJyKCZkc2ktPnBkZXYtPmRldiwK PiArCQkJIkZhaWxlZCB0byBzZXQgcGh5IGNsb2NrIHRvICVsZDogJWRcbiIsIHBoeV9jbG9jaywg cmV0KTsKPiArCX0KPiArCj4gKwkvKiBSZXNldCB0aGUgRFNJIGFuZCBhbGwgaXRzIGZpZm9zLiAq Lwo+ICsJRFNJX1BPUlRfV1JJVEUoQ1RSTCwKPiArCQkgICAgICAgRFNJX0NUUkxfU09GVF9SRVNF VF9DRkcgfAo+ICsJCSAgICAgICBEU0lfUE9SVF9CSVQoQ1RSTF9SRVNFVF9GSUZPUykpOwo+ICsK PiArCURTSV9QT1JUX1dSSVRFKENUUkwsCj4gKwkJICAgICAgIERTSV9DVFJMX0hTRFRfRU9UX0RJ U0FCTEUgfAo+ICsJCSAgICAgICBEU0lfQ1RSTF9SWF9MUERUX0VPVF9ESVNBQkxFKTsKPiArCj4g KwkvKiBDbGVhciBhbGwgc3RhdCBiaXRzIHNvIHdlIHNlZSB3aGF0IGhhcyBoYXBwZW5lZCBkdXJp bmcgZW5hYmxlLiAqLwo+ICsJRFNJX1BPUlRfV1JJVEUoU1RBVCwgRFNJX1BPUlRfUkVBRChTVEFU KSk7Cj4gKwo+ICsJLyogU2V0IEFGRSBDVFIwMC9DVFIxIHRvIHJlbGVhc2UgcG93ZXJkb3duIG9m IGFuYWxvZy4gKi8KPiArCWlmIChkc2ktPnBvcnQgPT0gMCkgewo+ICsJCXUzMiBhZmVjMCA9IChW QzRfU0VUX0ZJRUxEKDcsIERTSV9QSFlfQUZFQzBfUFRBVEFESikgfAo+ICsJCQkgICAgIFZDNF9T RVRfRklFTEQoNywgRFNJX1BIWV9BRkVDMF9DVEFUQURKKSk7Cj4gKwo+ICsJCWlmIChkc2ktPmxh bmVzIDwgMikKPiArCQkJYWZlYzAgfD0gRFNJMF9QSFlfQUZFQzBfUERfRExBTkUxOwo+ICsKPiAr CQlpZiAoIShkc2ktPm1vZGVfZmxhZ3MgJiBNSVBJX0RTSV9NT0RFX1ZJREVPKSkKPiArCQkJYWZl YzAgfD0gRFNJMF9QSFlfQUZFQzBfUkVTRVQ7Cj4gKwo+ICsJCURTSV9QT1JUX1dSSVRFKFBIWV9B RkVDMCwgYWZlYzApOwo+ICsKPiArCQlEU0lfUE9SVF9XUklURShQSFlfQUZFQzEsCj4gKwkJCSAg ICAgICBWQzRfU0VUX0ZJRUxEKDYsICBEU0kwX1BIWV9BRkVDMV9JRFJfRExBTkUxKSB8Cj4gKwkJ CSAgICAgICBWQzRfU0VUX0ZJRUxEKDYsICBEU0kwX1BIWV9BRkVDMV9JRFJfRExBTkUwKSB8Cj4g KwkJCSAgICAgICBWQzRfU0VUX0ZJRUxEKDYsICBEU0kwX1BIWV9BRkVDMV9JRFJfQ0xBTkUpKTsK PiArCX0gZWxzZSB7Cj4gKwkJdTMyIGFmZWMwID0gKFZDNF9TRVRfRklFTEQoNywgRFNJX1BIWV9B RkVDMF9QVEFUQURKKSB8Cj4gKwkJCSAgICAgVkM0X1NFVF9GSUVMRCg3LCBEU0lfUEhZX0FGRUMw X0NUQVRBREopIHwKPiArCQkJICAgICBWQzRfU0VUX0ZJRUxEKDYsIERTSTFfUEhZX0FGRUMwX0lE Ul9DTEFORSkgfAo+ICsJCQkgICAgIFZDNF9TRVRfRklFTEQoNiwgRFNJMV9QSFlfQUZFQzBfSURS X0RMQU5FMCkgfAo+ICsJCQkgICAgIFZDNF9TRVRfRklFTEQoNiwgRFNJMV9QSFlfQUZFQzBfSURS X0RMQU5FMSkgfAo+ICsJCQkgICAgIFZDNF9TRVRfRklFTEQoNiwgRFNJMV9QSFlfQUZFQzBfSURS X0RMQU5FMikgfAo+ICsJCQkgICAgIFZDNF9TRVRfRklFTEQoNiwgRFNJMV9QSFlfQUZFQzBfSURS X0RMQU5FMykpOwo+ICsKPiArCQlpZiAoZHNpLT5sYW5lcyA8IDQpCj4gKwkJCWFmZWMwIHw9IERT STFfUEhZX0FGRUMwX1BEX0RMQU5FMzsKPiArCQlpZiAoZHNpLT5sYW5lcyA8IDMpCj4gKwkJCWFm ZWMwIHw9IERTSTFfUEhZX0FGRUMwX1BEX0RMQU5FMjsKPiArCQlpZiAoZHNpLT5sYW5lcyA8IDIp Cj4gKwkJCWFmZWMwIHw9IERTSTFfUEhZX0FGRUMwX1BEX0RMQU5FMTsKPiArCj4gKwkJYWZlYzAg fD0gRFNJMV9QSFlfQUZFQzBfUkVTRVQ7Cj4gKwo+ICsJCURTSV9QT1JUX1dSSVRFKFBIWV9BRkVD MCwgYWZlYzApOwo+ICsKPiArCQlEU0lfUE9SVF9XUklURShQSFlfQUZFQzEsIDApOwo+ICsKPiAr CQkvKiBBRkVDIHJlc2V0IGhvbGQgdGltZSAqLwo+ICsJCW1kZWxheSgxKTsKPiArCX0KPiArCj4g KwlyZXQgPSBjbGtfcHJlcGFyZV9lbmFibGUoZHNpLT5lc2NhcGVfY2xvY2spOwo+ICsJaWYgKHJl dCkgewo+ICsJCURSTV9FUlJPUigiRmFpbGVkIHRvIHR1cm4gb24gRFNJIGVzY2FwZSBjbG9jazog JWRcbiIsIHJldCk7Cj4gKwkJcmV0dXJuOwo+ICsJfQo+ICsKPiArCXJldCA9IGNsa19wcmVwYXJl X2VuYWJsZShkc2ktPnBsbF9waHlfY2xvY2spOwo+ICsJaWYgKHJldCkgewo+ICsJCURSTV9FUlJP UigiRmFpbGVkIHRvIHR1cm4gb24gRFNJIFBMTDogJWRcbiIsIHJldCk7Cj4gKwkJcmV0dXJuOwo+ ICsJfQo+ICsKPiArCWhzX2Nsb2NrID0gY2xrX2dldF9yYXRlKGRzaS0+cGxsX3BoeV9jbG9jayk7 Cj4gKwo+ICsJLyogWWVzLCB3ZSBzZXQgdGhlIERTSTBQL0RTSTFQIHBpeGVsIGNsb2NrIHRvIHRo ZSBieXRlIHJhdGUsCj4gKwkgKiBub3QgdGhlIHBpeGVsIGNsb2NrIHJhdGUuICBEU0l4UCB0YWtl IGZyb20gdGhlIEFQSFkncyBieXRlLAo+ICsJICogRERSMiwgb3IgRERSNCBjbG9jayAod2UgdXNl IGJ5dGUpIGFuZCBmZWVkIGludG8gdGhlIFBWIGF0Cj4gKwkgKiB0aGF0IHJhdGUuICBTZXBhcmF0 ZWx5LCBhIHZhbHVlIGRlcml2ZWQgZnJvbSBQSVhfQ0xLX0RJVgo+ICsJICogYW5kIEhTX0NMS0Mg aXMgZmVkIGludG8gdGhlIFBWIHRvIGRpdmlkZSBkb3duIHRvIHRoZSBhY3R1YWwKPiArCSAqIHBp eGVsIGNsb2NrIGZvciBwdXNoaW5nIHBpeGVscyBpbnRvIERTSS4KPiArCSAqLwo+ICsJZHNpcF9j bG9jayA9IHBoeV9jbG9jayAvIDg7Cj4gKwlyZXQgPSBjbGtfc2V0X3JhdGUoZHNpLT5waXhlbF9j bG9jaywgZHNpcF9jbG9jayk7Cj4gKwlpZiAocmV0KSB7Cj4gKwkJZGV2X2VycihkZXYsICJGYWls ZWQgdG8gc2V0IHBpeGVsIGNsb2NrIHRvICVsZEh6OiAlZFxuIiwKPiArCQkJZHNpcF9jbG9jaywg cmV0KTsKPiArCX0KPiArCj4gKwlyZXQgPSBjbGtfcHJlcGFyZV9lbmFibGUoZHNpLT5waXhlbF9j bG9jayk7Cj4gKwlpZiAocmV0KSB7Cj4gKwkJRFJNX0VSUk9SKCJGYWlsZWQgdG8gdHVybiBvbiBE U0kgcGl4ZWwgY2xvY2s6ICVkXG4iLCByZXQpOwo+ICsJCXJldHVybjsKPiArCX0KPiArCj4gKwkv KiBIb3cgbWFueSBucyBvbmUgRFNJIHVuaXQgaW50ZXJ2YWwgaXMuICBOb3RlIHRoYXQgdGhlIGNs b2NrCj4gKwkgKiBpcyBERFIsIHNvIHRoZXJlJ3MgYW4gZXh0cmEgZGl2aWRlIGJ5IDIuCj4gKwkg Ki8KPiArCXVpX25zID0gRElWX1JPVU5EX1VQKDUwMDAwMDAwMCwgaHNfY2xvY2spOwo+ICsKPiAr CURTSV9QT1JUX1dSSVRFKEhTX0NMVDAsCj4gKwkJICAgICAgIFZDNF9TRVRfRklFTEQoZHNpX2hz X3RpbWluZyh1aV9ucywgMjYyLCAwKSwKPiArCQkJCSAgICAgRFNJX0hTX0NMVDBfQ1pFUk8pIHwK PiArCQkgICAgICAgVkM0X1NFVF9GSUVMRChkc2lfaHNfdGltaW5nKHVpX25zLCAwLCA4KSwKPiAr CQkJCSAgICAgRFNJX0hTX0NMVDBfQ1BSRSkgfAo+ICsJCSAgICAgICBWQzRfU0VUX0ZJRUxEKGRz aV9oc190aW1pbmcodWlfbnMsIDM4LCAwKSwKPiArCQkJCSAgICAgRFNJX0hTX0NMVDBfQ1BSRVAp KTsKPiArCj4gKwlEU0lfUE9SVF9XUklURShIU19DTFQxLAo+ICsJCSAgICAgICBWQzRfU0VUX0ZJ RUxEKGRzaV9oc190aW1pbmcodWlfbnMsIDYwLCAwKSwKPiArCQkJCSAgICAgRFNJX0hTX0NMVDFf Q1RSQUlMKSB8Cj4gKwkJICAgICAgIFZDNF9TRVRfRklFTEQoZHNpX2hzX3RpbWluZyh1aV9ucywg NjAsIDUyKSwKPiArCQkJCSAgICAgRFNJX0hTX0NMVDFfQ1BPU1QpKTsKPiArCj4gKwlEU0lfUE9S VF9XUklURShIU19DTFQyLAo+ICsJCSAgICAgICBWQzRfU0VUX0ZJRUxEKGRzaV9oc190aW1pbmco dWlfbnMsIDEwMDAwMDAsIDApLAo+ICsJCQkJICAgICBEU0lfSFNfQ0xUMl9XVVApKTsKPiArCj4g KwlEU0lfUE9SVF9XUklURShIU19ETFQzLAo+ICsJCSAgICAgICBWQzRfU0VUX0ZJRUxEKGRzaV9o c190aW1pbmcodWlfbnMsIDEwMCwgMCksCj4gKwkJCQkgICAgIERTSV9IU19ETFQzX0VYSVQpIHwK PiArCQkgICAgICAgVkM0X1NFVF9GSUVMRChkc2lfaHNfdGltaW5nKHVpX25zLCAxMDUsIDYpLAo+ ICsJCQkJICAgICBEU0lfSFNfRExUM19aRVJPKSB8Cj4gKwkJICAgICAgIFZDNF9TRVRfRklFTEQo ZHNpX2hzX3RpbWluZyh1aV9ucywgNDAsIDQpLAo+ICsJCQkJICAgICBEU0lfSFNfRExUM19QUkUp KTsKPiArCj4gKwlEU0lfUE9SVF9XUklURShIU19ETFQ0LAo+ICsJCSAgICAgICBWQzRfU0VUX0ZJ RUxEKGRzaV9oc190aW1pbmcodWlfbnMsIGxweCAqIEVTQ19USU1FX05TLCAwKSwKPiArCQkJCSAg ICAgRFNJX0hTX0RMVDRfTFBYKSB8Cj4gKwkJICAgICAgIFZDNF9TRVRfRklFTEQobWF4KGRzaV9o c190aW1pbmcodWlfbnMsIDAsIDgpLAo+ICsJCQkJCSBkc2lfaHNfdGltaW5nKHVpX25zLCA2MCwg NCkpLAo+ICsJCQkJICAgICBEU0lfSFNfRExUNF9UUkFJTCkgfAo+ICsJCSAgICAgICBWQzRfU0VU X0ZJRUxEKDAsIERTSV9IU19ETFQ0X0FOTEFUKSk7Cj4gKwo+ICsJRFNJX1BPUlRfV1JJVEUoSFNf RExUNSwgVkM0X1NFVF9GSUVMRChkc2lfaHNfdGltaW5nKHVpX25zLCAxMDAwLCA1MDAwKSwKPiAr CQkJCQkgICAgICBEU0lfSFNfRExUNV9JTklUKSk7Cj4gKwo+ICsJRFNJX1BPUlRfV1JJVEUoSFNf RExUNiwKPiArCQkgICAgICAgVkM0X1NFVF9GSUVMRChscHggKiA1LCBEU0lfSFNfRExUNl9UQV9H RVQpIHwKPiArCQkgICAgICAgVkM0X1NFVF9GSUVMRChscHgsIERTSV9IU19ETFQ2X1RBX1NVUkUp IHwKPiArCQkgICAgICAgVkM0X1NFVF9GSUVMRChscHggKiA0LCBEU0lfSFNfRExUNl9UQV9HTykg fAo+ICsJCSAgICAgICBWQzRfU0VUX0ZJRUxEKGxweCwgRFNJX0hTX0RMVDZfTFBfTFBYKSk7Cj4g Kwo+ICsJRFNJX1BPUlRfV1JJVEUoSFNfRExUNywKPiArCQkgICAgICAgVkM0X1NFVF9GSUVMRChk c2lfZXNjX3RpbWluZygxMDAwMDAwKSwKPiArCQkJCSAgICAgRFNJX0hTX0RMVDdfTFBfV1VQKSk7 Cj4gKwo+ICsJRFNJX1BPUlRfV1JJVEUoUEhZQywKPiArCQkgICAgICAgRFNJX1BIWUNfRExBTkUw X0VOQUJMRSB8Cj4gKwkJICAgICAgIChkc2ktPmxhbmVzID49IDIgPyBEU0lfUEhZQ19ETEFORTFf RU5BQkxFIDogMCkgfAo+ICsJCSAgICAgICAoZHNpLT5sYW5lcyA+PSAzID8gRFNJX1BIWUNfRExB TkUyX0VOQUJMRSA6IDApIHwKPiArCQkgICAgICAgKGRzaS0+bGFuZXMgPj0gNCA/IERTSV9QSFlD X0RMQU5FM19FTkFCTEUgOiAwKSB8Cj4gKwkJICAgICAgIERTSV9QT1JUX0JJVChQSFlDX0NMQU5F X0VOQUJMRSkgfAo+ICsJCSAgICAgICAoKGRzaS0+bW9kZV9mbGFncyAmIE1JUElfRFNJX0NMT0NL X05PTl9DT05USU5VT1VTKSA/Cj4gKwkJCTAgOiBEU0lfUE9SVF9CSVQoUEhZQ19IU19DTEtfQ09O VElOVU9VUykpIHwKPiArCQkgICAgICAgKGRzaS0+cG9ydCA9PSAwID8KPiArCQkJVkM0X1NFVF9G SUVMRChscHggLSAxLCBEU0kwX1BIWUNfRVNDX0NMS19MUERUKSA6Cj4gKwkJCVZDNF9TRVRfRklF TEQobHB4IC0gMSwgRFNJMV9QSFlDX0VTQ19DTEtfTFBEVCkpKTsKPiArCj4gKwlEU0lfUE9SVF9X UklURShDVFJMLAo+ICsJCSAgICAgICBEU0lfUE9SVF9SRUFEKENUUkwpIHwKPiArCQkgICAgICAg RFNJX0NUUkxfQ0FMX0JZVEUpOwo+ICsKPiArCS8qIEhTIHRpbWVvdXQgaW4gSFMgY2xvY2sgY3lj bGVzOiBkaXNhYmxlZC4gKi8KPiArCURTSV9QT1JUX1dSSVRFKEhTVFhfVE9fQ05ULCAwKTsKPiAr CS8qIExQIHJlY2VpdmUgdGltZW91dCBpbiBIUyBjbG9ja3MuICovCj4gKwlEU0lfUE9SVF9XUklU RShMUFJYX1RPX0NOVCwgMHhmZmZmZmYpOwo+ICsJLyogQnVzIHR1cm5hcm91bmQgdGltZW91dCAq Lwo+ICsJRFNJX1BPUlRfV1JJVEUoVEFfVE9fQ05ULCAxMDAwMDApOwo+ICsJLyogRGlzcGxheSBy ZXNldCBzZXF1ZW5jZSB0aW1lb3V0ICovCj4gKwlEU0lfUE9SVF9XUklURShQUl9UT19DTlQsIDEw MDAwMCk7Cj4gKwo+ICsJaWYgKGRzaS0+bW9kZV9mbGFncyAmIE1JUElfRFNJX01PREVfVklERU8p IHsKPiArCQlEU0lfUE9SVF9XUklURShESVNQMF9DVFJMLAo+ICsJCQkgICAgICAgVkM0X1NFVF9G SUVMRChkaXZpZGVyLCBEU0lfRElTUDBfUElYX0NMS19ESVYpIHwKPiArCQkJICAgICAgIFZDNF9T RVRfRklFTEQoZm9ybWF0LCBEU0lfRElTUDBfUEZPUk1BVCkgfAo+ICsJCQkgICAgICAgVkM0X1NF VF9GSUVMRChEU0lfRElTUDBfTFBfU1RPUF9QRVJGUkFNRSwKPiArCQkJCQkgICAgIERTSV9ESVNQ MF9MUF9TVE9QX0NUUkwpIHwKPiArCQkJICAgICAgIERTSV9ESVNQMF9TVF9FTkQgfAo+ICsJCQkg ICAgICAgRFNJX0RJU1AwX0VOQUJMRSk7Cj4gKwl9IGVsc2Ugewo+ICsJCURTSV9QT1JUX1dSSVRF KERJU1AwX0NUUkwsCj4gKwkJCSAgICAgICBEU0lfRElTUDBfQ09NTUFORF9NT0RFIHwKPiArCQkJ ICAgICAgIERTSV9ESVNQMF9FTkFCTEUpOwo+ICsJfQo+ICsKPiArCS8qIFNldCB1cCBESVNQMSBm b3IgdHJhbnNmZXJyaW5nIGxvbmcgY29tbWFuZCBwYXlsb2FkcyB0aHJvdWdoCj4gKwkgKiB0aGUg cGl4Zmlmby4KPiArCSAqLwo+ICsJRFNJX1BPUlRfV1JJVEUoRElTUDFfQ1RSTCwKPiArCQkgICAg ICAgVkM0X1NFVF9GSUVMRChEU0lfRElTUDFfUEZPUk1BVF8zMkJJVF9MRSwKPiArCQkJCSAgICAg RFNJX0RJU1AxX1BGT1JNQVQpIHwKPiArCQkgICAgICAgRFNJX0RJU1AxX0VOQUJMRSk7Cj4gKwo+ ICsJLyogVW5nYXRlIHRoZSBibG9jay4gKi8KPiArCWlmIChkc2ktPnBvcnQgPT0gMCkKPiArCQlE U0lfUE9SVF9XUklURShDVFJMLCBEU0lfUE9SVF9SRUFEKENUUkwpIHwgRFNJMF9DVFJMX0NUUkww KTsKPiArCWVsc2UKPiArCQlEU0lfUE9SVF9XUklURShDVFJMLCBEU0lfUE9SVF9SRUFEKENUUkwp IHwgRFNJMV9DVFJMX0VOKTsKPiArCj4gKwkvKiBCcmluZyBBRkUgb3V0IG9mIHJlc2V0LiAqLwo+ ICsJaWYgKGRzaS0+cG9ydCA9PSAwKSB7Cj4gKwl9IGVsc2Ugewo+ICsJCURTSV9QT1JUX1dSSVRF KFBIWV9BRkVDMCwKPiArCQkJICAgICAgIERTSV9QT1JUX1JFQUQoUEhZX0FGRUMwKSAmCj4gKwkJ CSAgICAgICB+RFNJMV9QSFlfQUZFQzBfUkVTRVQpOwo+ICsJfQo+ICsKPiArCXZjNF9kc2lfdWxw cyhkc2ksIGZhbHNlKTsKPiArCj4gKwlpZiAoZGVidWdfZHVtcF9yZWdzKSB7Cj4gKwkJRFJNX0lO Rk8oIkRTSSByZWdzIGFmdGVyOlxuIik7Cj4gKwkJdmM0X2RzaV9kdW1wX3JlZ3MoZHNpKTsKPiAr CX0KPiArCj4gKwlyZXQgPSBkcm1fcGFuZWxfZW5hYmxlKGRzaS0+cGFuZWwpOwo+ICsJaWYgKHJl dCkgewo+ICsJCURSTV9FUlJPUigiUGFuZWwgZmFpbGVkIHRvIGVuYWJsZVxuIik7Cj4gKwkJZHJt X3BhbmVsX3VucHJlcGFyZShkc2ktPnBhbmVsKTsKPiArCQlyZXR1cm47Cj4gKwl9Cj4gK30KPiAr Cj4gK3N0YXRpYyBzc2l6ZV90IHZjNF9kc2lfaG9zdF90cmFuc2ZlcihzdHJ1Y3QgbWlwaV9kc2lf aG9zdCAqaG9zdCwKPiArCQkJCSAgICAgY29uc3Qgc3RydWN0IG1pcGlfZHNpX21zZyAqbXNnKQo+ ICt7Cj4gKwlzdHJ1Y3QgdmM0X2RzaSAqZHNpID0gaG9zdF90b19kc2koaG9zdCk7Cj4gKwlzdHJ1 Y3QgbWlwaV9kc2lfcGFja2V0IHBhY2tldDsKPiArCXUzMiBwa3RoID0gMCwgcGt0YyA9IDA7Cj4g KwlpbnQgaSwgcmV0Owo+ICsJYm9vbCBpc19sb25nID0gbWlwaV9kc2lfcGFja2V0X2Zvcm1hdF9p c19sb25nKG1zZy0+dHlwZSk7Cj4gKwl1MzIgY21kX2ZpZm9fbGVuID0gMCwgcGl4X2ZpZm9fbGVu ID0gMDsKPiArCj4gKwltaXBpX2RzaV9jcmVhdGVfcGFja2V0KCZwYWNrZXQsIG1zZyk7Cj4gKwo+ ICsJcGt0aCB8PSBWQzRfU0VUX0ZJRUxEKHBhY2tldC5oZWFkZXJbMF0sIERTSV9UWFBLVDFIX0JD X0RUKTsKPiArCXBrdGggfD0gVkM0X1NFVF9GSUVMRChwYWNrZXQuaGVhZGVyWzFdIHwKPiArCQkJ ICAgICAgKHBhY2tldC5oZWFkZXJbMl0gPDwgOCksCj4gKwkJCSAgICAgIERTSV9UWFBLVDFIX0JD X1BBUkFNKTsKPiArCWlmIChpc19sb25nKSB7Cj4gKwkJLyogRGl2aWRlIGRhdGEgYWNyb3NzIHRo ZSB2YXJpb3VzIEZJRk9zIHdlIGhhdmUgYXZhaWxhYmxlLgo+ICsJCSAqIFRoZSBjb21tYW5kIEZJ Rk8gdGFrZXMgYnl0ZS1vcmllbnRlZCBkYXRhLCBidXQgaXMgb2YKPiArCQkgKiBsaW1pdGVkIHNp emUuIFRoZSBwaXhlbCBGSUZPIChuZXZlciBhY3R1YWxseSB1c2VkIGZvcgo+ICsJCSAqIHBpeGVs IGRhdGEgaW4gcmVhbGl0eSkgaXMgd29yZCBvcmllbnRlZCwgYW5kIHN1YnN0YW50aWFsbHkKPiAr CQkgKiBsYXJnZXIuIFNvLCB3ZSB1c2UgdGhlIHBpeGVsIEZJRk8gZm9yIG1vc3Qgb2YgdGhlIGRh dGEsCj4gKwkJICogc2VuZGluZyB0aGUgcmVzaWR1YWwgYnl0ZXMgaW4gdGhlIGNvbW1hbmQgRklG TyBhdCB0aGUgc3RhcnQuCj4gKwkJICoKPiArCQkgKiBXaXRoIHRoaXMgYXJyYW5nZW1lbnQsIHRo ZSBjb21tYW5kIEZJRk8gd2lsbCBuZXZlciBnZXQgZnVsbC4KPiArCQkgKi8KCkkgd29uZGVyZWQg d2hldGhlciB0aGlzIGlzIHNvbWV0aGluZyB0aGUgZHNpIGNvcmUgc2hvdWxkIG1heWJlIG9wdGlv bmFsbHkKZG8sIGJ1dCBkb2Vzbid0IHNlZW0gdG8gYmUgYSBjb21tb24gcGF0dGVybiBsb29raW5n IGF0IGV4aXN0aW5nIHRyYW5zZmVyCmZ1bmN0aW9ucy4KCj4gKwkJaWYgKHBhY2tldC5wYXlsb2Fk X2xlbmd0aCA8PSAxNikgewo+ICsJCQljbWRfZmlmb19sZW4gPSBwYWNrZXQucGF5bG9hZF9sZW5n dGg7Cj4gKwkJCXBpeF9maWZvX2xlbiA9IDA7Cj4gKwkJfSBlbHNlIHsKPiArCQkJY21kX2ZpZm9f bGVuID0gKHBhY2tldC5wYXlsb2FkX2xlbmd0aCAlCj4gKwkJCQkJRFNJX1BJWF9GSUZPX1dJRFRI KTsKPiArCQkJcGl4X2ZpZm9fbGVuID0gKChwYWNrZXQucGF5bG9hZF9sZW5ndGggLSBjbWRfZmlm b19sZW4pIC8KPiArCQkJCQlEU0lfUElYX0ZJRk9fV0lEVEgpOwo+ICsJCX0KPiArCj4gKwkJV0FS Tl9PTl9PTkNFKHBpeF9maWZvX2xlbiA+PSBEU0lfUElYX0ZJRk9fREVQVEgpOwo+ICsKPiArCQlw a3RoIHw9IFZDNF9TRVRfRklFTEQoY21kX2ZpZm9fbGVuLCBEU0lfVFhQS1QxSF9CQ19DTURGSUZP KTsKPiArCX0KPiArCj4gKwlpZiAobXNnLT5yeF9sZW4pIHsKPiArCQlwa3RjIHw9IFZDNF9TRVRf RklFTEQoRFNJX1RYUEtUMUNfQ01EX0NUUkxfUlgsCj4gKwkJCQkgICAgICBEU0lfVFhQS1QxQ19D TURfQ1RSTCk7Cj4gKwl9IGVsc2Ugewo+ICsJCXBrdGMgfD0gVkM0X1NFVF9GSUVMRChEU0lfVFhQ S1QxQ19DTURfQ1RSTF9UWCwKPiArCQkJCSAgICAgIERTSV9UWFBLVDFDX0NNRF9DVFJMKTsKPiAr CX0KPiArCj4gKwlmb3IgKGkgPSAwOyBpIDwgY21kX2ZpZm9fbGVuOyBpKyspCj4gKwkJRFNJX1BP UlRfV1JJVEUoVFhQS1RfQ01EX0ZJRk8sIHBhY2tldC5wYXlsb2FkW2ldKTsKPiArCWZvciAoaSA9 IDA7IGkgPCBwaXhfZmlmb19sZW47IGkrKykgewo+ICsJCWNvbnN0IHU4ICpwaXggPSBwYWNrZXQu cGF5bG9hZCArIGNtZF9maWZvX2xlbiArIGkgKiA0Owo+ICsKPiArCQlEU0lfUE9SVF9XUklURShU WFBLVF9QSVhfRklGTywKPiArCQkJICAgICAgIHBpeFswXSB8Cj4gKwkJCSAgICAgICBwaXhbMV0g PDwgOCB8Cj4gKwkJCSAgICAgICBwaXhbMl0gPDwgMTYgfAo+ICsJCQkgICAgICAgcGl4WzNdIDw8 IDI0KTsKPiArCX0KPiArCj4gKwlpZiAobXNnLT5mbGFncyAmIE1JUElfRFNJX01TR19VU0VfTFBN KQo+ICsJCXBrdGMgfD0gRFNJX1RYUEtUMUNfQ01EX01PREVfTFA7Cj4gKwlpZiAoaXNfbG9uZykK PiArCQlwa3RjIHw9IERTSV9UWFBLVDFDX0NNRF9UWVBFX0xPTkc7Cj4gKwo+ICsJLyogU2VuZCBv bmUgY29weSBvZiB0aGUgcGFja2V0LiAgTGFyZ2VyIHJlcGVhdHMgYXJlIHVzZWQgZm9yIHBpeGVs Cj4gKwkgKiBkYXRhIGluIGNvbW1hbmQgbW9kZS4KPiArCSAqLwo+ICsJcGt0YyB8PSBWQzRfU0VU X0ZJRUxEKDEsIERTSV9UWFBLVDFDX0NNRF9SRVBFQVQpOwo+ICsKPiArCXBrdGMgfD0gRFNJX1RY UEtUMUNfQ01EX0VOOwo+ICsJaWYgKHBpeF9maWZvX2xlbikgewo+ICsJCXBrdGMgfD0gVkM0X1NF VF9GSUVMRChEU0lfVFhQS1QxQ19ESVNQTEFZX05PX1NFQ09OREFSWSwKPiArCQkJCSAgICAgIERT SV9UWFBLVDFDX0RJU1BMQVlfTk8pOwo+ICsJfSBlbHNlIHsKPiArCQlwa3RjIHw9IFZDNF9TRVRf RklFTEQoRFNJX1RYUEtUMUNfRElTUExBWV9OT19TSE9SVCwKPiArCQkJCSAgICAgIERTSV9UWFBL VDFDX0RJU1BMQVlfTk8pOwo+ICsJfQo+ICsKPiArCS8qIEVuYWJsZSB0aGUgYXBwcm9wcmlhdGUg aW50ZXJydXB0IGZvciB0aGUgdHJhbnNmZXIgY29tcGxldGlvbi4gKi8KPiArCWRzaS0+eGZlcl9y ZXN1bHQgPSAwOwo+ICsJcmVpbml0X2NvbXBsZXRpb24oJmRzaS0+eGZlcl9jb21wbGV0aW9uKTsK PiArCURTSV9QT1JUX1dSSVRFKElOVF9TVEFULCBEU0kxX0lOVF9UWFBLVDFfRE9ORSB8IERTSTFf SU5UX1BIWV9ESVJfUlRGKTsKPiArCWlmIChtc2ctPnJ4X2xlbikgewo+ICsJCURTSV9QT1JUX1dS SVRFKElOVF9FTiwgKERTSTFfSU5URVJSVVBUU19BTFdBWVNfRU5BQkxFRCB8Cj4gKwkJCQkJRFNJ MV9JTlRfUEhZX0RJUl9SVEYpKTsKPiArCX0gZWxzZSB7Cj4gKwkJRFNJX1BPUlRfV1JJVEUoSU5U X0VOLCAoRFNJMV9JTlRFUlJVUFRTX0FMV0FZU19FTkFCTEVEIHwKPiArCQkJCQlEU0kxX0lOVF9U WFBLVDFfRE9ORSkpOwo+ICsJfQo+ICsKPiArCS8qIFNlbmQgdGhlIHBhY2tldC4gKi8KPiArCURT SV9QT1JUX1dSSVRFKFRYUEtUMUgsIHBrdGgpOwo+ICsJRFNJX1BPUlRfV1JJVEUoVFhQS1QxQywg cGt0Yyk7Cj4gKwo+ICsJaWYgKCF3YWl0X2Zvcl9jb21wbGV0aW9uX3RpbWVvdXQoJmRzaS0+eGZl cl9jb21wbGV0aW9uLAo+ICsJCQkJCSBtc2Vjc190b19qaWZmaWVzKDEwMDApKSkgewo+ICsJCWRl dl9lcnIoJmRzaS0+cGRldi0+ZGV2LCAidHJhbnNmZXIgaW50ZXJydXB0IHdhaXQgdGltZW91dCIp Owo+ICsJCWRldl9lcnIoJmRzaS0+cGRldi0+ZGV2LCAiaW5zdGF0OiAweCUwOHhcbiIsCj4gKwkJ CURTSV9QT1JUX1JFQUQoSU5UX1NUQVQpKTsKPiArCQlyZXQgPSAtRVRJTUVET1VUOwo+ICsJfSBl bHNlIHsKPiArCQlyZXQgPSBkc2ktPnhmZXJfcmVzdWx0Owo+ICsJfQo+ICsKPiArCURTSV9QT1JU X1dSSVRFKElOVF9FTiwgRFNJMV9JTlRFUlJVUFRTX0FMV0FZU19FTkFCTEVEKTsKPiArCj4gKwlp ZiAocmV0KQo+ICsJCWdvdG8gcmVzZXRfZmlmb19hbmRfcmV0dXJuOwo+ICsKPiArCWlmIChyZXQg PT0gMCAmJiBtc2ctPnJ4X2xlbikgewo+ICsJCXUzMiByeHBrdDFoID0gRFNJX1BPUlRfUkVBRChS WFBLVDFIKTsKPiArCQl1OCAqbXNnX3J4ID0gbXNnLT5yeF9idWY7Cj4gKwo+ICsJCWlmIChyeHBr dDFoICYgRFNJX1JYUEtUMUhfUEtUX1RZUEVfTE9ORykgewo+ICsJCQl1MzIgcnhsZW4gPSBWQzRf R0VUX0ZJRUxEKHJ4cGt0MWgsCj4gKwkJCQkJCSAgRFNJX1JYUEtUMUhfQkNfUEFSQU0pOwo+ICsK PiArCQkJaWYgKHJ4bGVuICE9IG1zZy0+cnhfbGVuKSB7Cj4gKwkJCQlEUk1fRVJST1IoIkRTSSBy ZXR1cm5lZCAlZGIsIGV4cGVjdGluZyAlZGJcbiIsCj4gKwkJCQkJICByeGxlbiwgKGludCltc2ct PnJ4X2xlbik7Cj4gKwkJCQlyZXQgPSAtRU5YSU87Cj4gKwkJCQlnb3RvIHJlc2V0X2ZpZm9fYW5k X3JldHVybjsKPiArCQkJfQo+ICsKPiArCQkJZm9yIChpID0gMDsgaSA8IG1zZy0+cnhfbGVuOyBp KyspCj4gKwkJCQltc2dfcnhbaV0gPSBEU0lfUkVBRChEU0kxX1JYUEtUX0ZJRk8pOwo+ICsJCX0g ZWxzZSB7Cj4gKwkJCS8qIEZJTklTSE1FOiBIYW5kbGUgQVdFUiAqLwo+ICsKPiArCQkJbXNnX3J4 WzBdID0gVkM0X0dFVF9GSUVMRChyeHBrdDFoLAo+ICsJCQkJCQkgIERTSV9SWFBLVDFIX1NIT1JU XzApOwo+ICsJCQlpZiAobXNnLT5yeF9sZW4gPiAxKSB7Cj4gKwkJCQltc2dfcnhbMV0gPSBWQzRf R0VUX0ZJRUxEKHJ4cGt0MWgsCj4gKwkJCQkJCQkgIERTSV9SWFBLVDFIX1NIT1JUXzEpOwo+ICsJ CQl9Cj4gKwkJfQo+ICsJfQo+ICsKPiArCXJldHVybiByZXQ7Cj4gKwo+ICtyZXNldF9maWZvX2Fu ZF9yZXR1cm46Cj4gKwlEUk1fRVJST1IoIkRTSSB0cmFuc2ZlciBmYWlsZWQsIHJlc2V0dGluZzog JWRcbiIsIHJldCk7Cj4gKwo+ICsJRFNJX1BPUlRfV1JJVEUoVFhQS1QxQywgRFNJX1BPUlRfUkVB RChUWFBLVDFDKSAmIH5EU0lfVFhQS1QxQ19DTURfRU4pOwo+ICsJdWRlbGF5KDEpOwo+ICsJRFNJ X1BPUlRfV1JJVEUoQ1RSTCwKPiArCQkgICAgICAgRFNJX1BPUlRfUkVBRChDVFJMKSB8Cj4gKwkJ ICAgICAgIERTSV9QT1JUX0JJVChDVFJMX1JFU0VUX0ZJRk9TKSk7Cj4gKwo+ICsJRFNJX1BPUlRf V1JJVEUoVFhQS1QxQywgMCk7Cj4gKwlEU0lfUE9SVF9XUklURShJTlRfRU4sIERTSTFfSU5URVJS VVBUU19BTFdBWVNfRU5BQkxFRCk7Cj4gKwlyZXR1cm4gcmV0Owo+ICt9Cj4gKwo+ICtzdGF0aWMg aW50IHZjNF9kc2lfaG9zdF9hdHRhY2goc3RydWN0IG1pcGlfZHNpX2hvc3QgKmhvc3QsCj4gKwkJ CSAgICAgICBzdHJ1Y3QgbWlwaV9kc2lfZGV2aWNlICpkZXZpY2UpCj4gK3sKPiArCXN0cnVjdCB2 YzRfZHNpICpkc2kgPSBob3N0X3RvX2RzaShob3N0KTsKPiArCWludCByZXQgPSAwOwo+ICsKPiAr CWRzaS0+bGFuZXMgPSBkZXZpY2UtPmxhbmVzOwo+ICsJZHNpLT5jaGFubmVsID0gZGV2aWNlLT5j aGFubmVsOwo+ICsJZHNpLT5mb3JtYXQgPSBkZXZpY2UtPmZvcm1hdDsKPiArCWRzaS0+bW9kZV9m bGFncyA9IGRldmljZS0+bW9kZV9mbGFnczsKPiArCj4gKwlpZiAoIShkc2ktPm1vZGVfZmxhZ3Mg JiBNSVBJX0RTSV9NT0RFX1ZJREVPKSkgewo+ICsJCWRldl9lcnIoJmRzaS0+cGRldi0+ZGV2LAo+ ICsJCQkiT25seSBWSURFTyBtb2RlIHBhbmVscyBzdXBwb3J0ZWQgY3VycmVudGx5LlxuIik7Cj4g KwkJcmV0dXJuIDA7Cj4gKwl9Cj4gKwo+ICsJZHNpLT5wYW5lbCA9IG9mX2RybV9maW5kX3BhbmVs KGRldmljZS0+ZGV2Lm9mX25vZGUpOwo+ICsJaWYgKCFkc2ktPnBhbmVsKQo+ICsJCXJldHVybiAw Owo+ICsKPiArCXJldCA9IGRybV9wYW5lbF9hdHRhY2goZHNpLT5wYW5lbCwgZHNpLT5jb25uZWN0 b3IpOwo+ICsJaWYgKHJldCAhPSAwKQo+ICsJCXJldHVybiByZXQ7Cj4gKwo+ICsJZHJtX2hlbHBl cl9ocGRfaXJxX2V2ZW50KGRzaS0+Y29ubmVjdG9yLT5kZXYpOwo+ICsKPiArCXJldHVybiAwOwo+ ICt9Cj4gKwo+ICtzdGF0aWMgaW50IHZjNF9kc2lfaG9zdF9kZXRhY2goc3RydWN0IG1pcGlfZHNp X2hvc3QgKmhvc3QsCj4gKwkJCSAgICAgICBzdHJ1Y3QgbWlwaV9kc2lfZGV2aWNlICpkZXZpY2Up Cj4gK3sKPiArCXN0cnVjdCB2YzRfZHNpICpkc2kgPSBob3N0X3RvX2RzaShob3N0KTsKPiArCj4g KwlpZiAoZHNpLT5wYW5lbCkgewo+ICsJCWludCByZXQgPSBkcm1fcGFuZWxfZGV0YWNoKGRzaS0+ cGFuZWwpOwo+ICsKPiArCQlpZiAocmV0KQo+ICsJCQlyZXR1cm4gcmV0Owo+ICsKPiArCQlkc2kt PnBhbmVsID0gTlVMTDsKPiArCj4gKwkJZHJtX2hlbHBlcl9ocGRfaXJxX2V2ZW50KGRzaS0+Y29u bmVjdG9yLT5kZXYpOwo+ICsJfQo+ICsKPiArCXJldHVybiAwOwo+ICt9Cj4gKwo+ICtzdGF0aWMg Y29uc3Qgc3RydWN0IG1pcGlfZHNpX2hvc3Rfb3BzIHZjNF9kc2lfaG9zdF9vcHMgPSB7Cj4gKwku YXR0YWNoID0gdmM0X2RzaV9ob3N0X2F0dGFjaCwKPiArCS5kZXRhY2ggPSB2YzRfZHNpX2hvc3Rf ZGV0YWNoLAoKVGhlcmUgc2VlbXMgdG8gYmUgYSBsb3Qgb2YgY2FyZ28tY3VsdGluZyBnb2luZyBv biB3aXRoIGF0dGFjaC9kZXRhY2gsIGFuZApJIGdldCBhIGJpdCB0aGUgZmVlbGluZyB0aGF0IHJl ZmFjdG9yaW5nIHRoaXMgaW50byBhIHN0YW5kYXJkIHdheSB0byBkbyBpdAooaW5jbHVkaW5nIHRo ZSBvZi9kdCBib2lsZXJwbGF0ZSwgd2l0aCBhbiBleWUgdG93YXJkcyBzdGFuZGFyZGl6aW5nIHRo ZQpiaW5kaW5kcykgd291bGQgYmUgZ29vZC4KCkFsc28sIHByb3BlciBrZXJuZWxkb2MgZm9yIHRo ZXNlIGNhbGxiYWNrcyBpbnN0ZWFkIG9mIHRoZSBvbmVsaW5lcyAod2UgY2FuCmRvIG11bHRpbGlu ZSBpbmxpbmUgY29tbWVudHMgbm93LCB3aXRoIGZvcm1hdHRpbmchKSB3b3VsZCBiZSBncmVhdC4K Cj4gKwkudHJhbnNmZXIgPSB2YzRfZHNpX2hvc3RfdHJhbnNmZXIsCgpoaXNpbGljb24gZG9lc24n dCBldmVuIGhhdmUgYSB0cmFuc2ZlciBmdW5jdGlvbiwgSSBndWVzcyBpdCB3b3JrcyBieQptYWdp Yy4KCj4gK307Cj4gKwo+ICtzdGF0aWMgY29uc3Qgc3RydWN0IGRybV9lbmNvZGVyX2hlbHBlcl9m dW5jcyB2YzRfZHNpX2VuY29kZXJfaGVscGVyX2Z1bmNzID0gewo+ICsJLmRpc2FibGUgPSB2YzRf ZHNpX2VuY29kZXJfZGlzYWJsZSwKPiArCS5lbmFibGUgPSB2YzRfZHNpX2VuY29kZXJfZW5hYmxl LAo+ICt9Owo+ICsKPiArc3RhdGljIGNvbnN0IHN0cnVjdCBvZl9kZXZpY2VfaWQgdmM0X2RzaV9k dF9tYXRjaFtdID0gewo+ICsJeyAuY29tcGF0aWJsZSA9ICJicmNtLGJjbTI4MzUtZHNpMSIsICh2 b2lkICopKHVpbnRwdHJfdCkxIH0sCj4gKwl7fQo+ICt9Owo+ICsKPiArc3RhdGljIHZvaWQgZHNp X2hhbmRsZV9lcnJvcihzdHJ1Y3QgdmM0X2RzaSAqZHNpLAo+ICsJCQkgICAgIGlycXJldHVybl90 ICpyZXQsIHUzMiBzdGF0LCB1MzIgYml0LAo+ICsJCQkgICAgIGNvbnN0IGNoYXIgKnR5cGUpCj4g K3sKPiArCWlmICghKHN0YXQgJiBiaXQpKQo+ICsJCXJldHVybjsKPiArCj4gKwlEUk1fRVJST1Io IkRTSSVkOiAlcyBlcnJvclxuIiwgZHNpLT5wb3J0LCB0eXBlKTsKPiArCSpyZXQgPSBJUlFfSEFO RExFRDsKPiArfQo+ICsKPiArc3RhdGljIGlycXJldHVybl90IHZjNF9kc2lfaXJxX2hhbmRsZXIo aW50IGlycSwgdm9pZCAqZGF0YSkKPiArewo+ICsJc3RydWN0IHZjNF9kc2kgKmRzaSA9IGRhdGE7 Cj4gKwl1MzIgc3RhdCA9IERTSV9QT1JUX1JFQUQoSU5UX1NUQVQpOwo+ICsJaXJxcmV0dXJuX3Qg cmV0ID0gSVJRX05PTkU7Cj4gKwo+ICsJRFNJX1BPUlRfV1JJVEUoSU5UX1NUQVQsIHN0YXQpOwo+ ICsKPiArCWRzaV9oYW5kbGVfZXJyb3IoZHNpLCAmcmV0LCBzdGF0LAo+ICsJCQkgRFNJMV9JTlRf RVJSX1NZTkNfRVNDLCAiTFBEVCBzeW5jIik7Cj4gKwlkc2lfaGFuZGxlX2Vycm9yKGRzaSwgJnJl dCwgc3RhdCwKPiArCQkJIERTSTFfSU5UX0VSUl9DT05UUk9MLCAiZGF0YSBsYW5lIDAgc2VxdWVu Y2UiKTsKPiArCWRzaV9oYW5kbGVfZXJyb3IoZHNpLCAmcmV0LCBzdGF0LAo+ICsJCQkgRFNJMV9J TlRfRVJSX0NPTlRfTFAwLCAiTFAwIGNvbnRlbnRpb24iKTsKPiArCWRzaV9oYW5kbGVfZXJyb3Io ZHNpLCAmcmV0LCBzdGF0LAo+ICsJCQkgRFNJMV9JTlRfRVJSX0NPTlRfTFAxLCAiTFAxIGNvbnRl bnRpb24iKTsKPiArCWRzaV9oYW5kbGVfZXJyb3IoZHNpLCAmcmV0LCBzdGF0LAo+ICsJCQkgRFNJ MV9JTlRfSFNUWF9UTywgIkhTVFggdGltZW91dCIpOwo+ICsJZHNpX2hhbmRsZV9lcnJvcihkc2ks ICZyZXQsIHN0YXQsCj4gKwkJCSBEU0kxX0lOVF9MUFJYX1RPLCAiTFBSWCB0aW1lb3V0Iik7Cj4g Kwlkc2lfaGFuZGxlX2Vycm9yKGRzaSwgJnJldCwgc3RhdCwKPiArCQkJIERTSTFfSU5UX1RBX1RP LCAidHVybmFyb3VuZCB0aW1lb3V0Iik7Cj4gKwlkc2lfaGFuZGxlX2Vycm9yKGRzaSwgJnJldCwg c3RhdCwKPiArCQkJIERTSTFfSU5UX1BSX1RPLCAicGVyaXBoZXJhbCByZXNldCB0aW1lb3V0Iik7 Cj4gKwo+ICsJaWYgKHN0YXQgJiAoRFNJMV9JTlRfVFhQS1QxX0RPTkUgfCBEU0kxX0lOVF9QSFlf RElSX1JURikpIHsKPiArCQljb21wbGV0ZSgmZHNpLT54ZmVyX2NvbXBsZXRpb24pOwo+ICsJCXJl dCA9IElSUV9IQU5ETEVEOwo+ICsJfSBlbHNlIGlmIChzdGF0ICYgRFNJMV9JTlRfSFNUWF9UTykg ewo+ICsJCWNvbXBsZXRlKCZkc2ktPnhmZXJfY29tcGxldGlvbik7Cj4gKwkJZHNpLT54ZmVyX3Jl c3VsdCA9IC1FVElNRURPVVQ7Cj4gKwkJcmV0ID0gSVJRX0hBTkRMRUQ7Cj4gKwl9Cj4gKwo+ICsJ cmV0dXJuIHJldDsKPiArfQo+ICsKPiArLyoqCj4gKyAqIEV4cG9zZXMgY2xvY2tzIGdlbmVyYXRl ZCBieSB0aGUgYW5hbG9nIFBIWSB0aGF0IGFyZSBjb25zdW1lZCBieQo+ICsgKiBDUFJNQU4gKGNs ay1iY20yODM1LmMpLgo+ICsgKi8KPiArc3RhdGljIGludAo+ICt2YzRfZHNpX2luaXRfcGh5X2Ns b2NrcyhzdHJ1Y3QgdmM0X2RzaSAqZHNpKQo+ICt7Cj4gKwlzdHJ1Y3QgZGV2aWNlICpkZXYgPSAm ZHNpLT5wZGV2LT5kZXY7Cj4gKwljb25zdCBjaGFyICpwYXJlbnRfbmFtZSA9IF9fY2xrX2dldF9u YW1lKGRzaS0+cGxsX3BoeV9jbG9jayk7Cj4gKwlzdGF0aWMgY29uc3Qgc3RydWN0IHsKPiArCQlj b25zdCBjaGFyICpkc2kwX25hbWUsICpkc2kxX25hbWU7Cj4gKwkJaW50IGRpdjsKPiArCX0gcGh5 X2Nsb2Nrc1tdID0gewo+ICsJCXsgImRzaTBfYnl0ZSIsICJkc2kxX2J5dGUiLCA4IH0sCj4gKwkJ eyAiZHNpMF9kZHIyIiwgImRzaTFfZGRyMiIsIDQgfSwKPiArCQl7ICJkc2kwX2RkciIsICJkc2kx X2RkciIsIDIgfSwKPiArCX07Cj4gKwlpbnQgaTsKPiArCj4gKwlkc2ktPmNsa19vbmVjZWxsLmNs a19udW0gPSBBUlJBWV9TSVpFKHBoeV9jbG9ja3MpOwo+ICsJZHNpLT5jbGtfb25lY2VsbC5jbGtz ID0gZGV2bV9rY2FsbG9jKGRldiwKPiArCQkJCQkgICAgIGRzaS0+Y2xrX29uZWNlbGwuY2xrX251 bSwKPiArCQkJCQkgICAgIHNpemVvZigqZHNpLT5jbGtfb25lY2VsbC5jbGtzKSwKPiArCQkJCQkg ICAgIEdGUF9LRVJORUwpOwo+ICsJaWYgKCFkc2ktPmNsa19vbmVjZWxsLmNsa3MpCj4gKwkJcmV0 dXJuIC1FTk9NRU07Cj4gKwo+ICsJZm9yIChpID0gMDsgaSA8IEFSUkFZX1NJWkUocGh5X2Nsb2Nr cyk7IGkrKykgewo+ICsJCXN0cnVjdCBjbGtfZml4ZWRfZmFjdG9yICpmaXggPSAmZHNpLT5waHlf Y2xvY2tzW2ldOwo+ICsJCXN0cnVjdCBjbGtfaW5pdF9kYXRhIGluaXQ7Cj4gKwkJc3RydWN0IGNs ayAqY2xrOwo+ICsKPiArCQkvKiBXZSBqdXN0IHVzZSBjb3JlIGZpeGVkIGZhY3RvciBjbG9jayBv cHMgZm9yIHRoZSBQSFkKPiArCQkgKiBjbG9ja3MuICBUaGUgY2xvY2tzIGFyZSBhY3R1YWxseSBn YXRlZCBieSB0aGUKPiArCQkgKiBQSFlfQUZFQzBfRERSQ0xLX0VOIGJpdHMsIHdoaWNoIHdlIHNo b3VsZCBiZQo+ICsJCSAqIHNldHRpbmcgaWYgd2UgdXNlIHRoZSBERFIvRERSMiBjbG9ja3MuICBI b3dldmVyLAo+ICsJCSAqIHZjNF9kc2lfZW5jb2Rlcl9lbmFibGUoKSBpcyBzZXR0aW5nIHVwIGJv dGggQUZFQzAsCj4gKwkJICogc2V0dGluZyBib3RoIG91ciBwYXJlbnQgRFNJIFBMTCdzIHJhdGUg YW5kIHRoaXMKPiArCQkgKiBjbG9jaydzIHJhdGUsIHNvIGl0IGtub3dzIGlmIEREUi9ERFIyIGFy ZSBnb2luZyB0bwo+ICsJCSAqIGJlIHVzZWQgYW5kIGNvdWxkIGVuYWJsZSB0aGUgZ2F0ZXMgaXRz ZWxmLgo+ICsJCSAqLwo+ICsJCWZpeC0+bXVsdCA9IDE7Cj4gKwkJZml4LT5kaXYgPSBwaHlfY2xv Y2tzW2ldLmRpdjsKPiArCQlmaXgtPmh3LmluaXQgPSAmaW5pdDsKPiArCj4gKwkJbWVtc2V0KCZp bml0LCAwLCBzaXplb2YoaW5pdCkpOwo+ICsJCWluaXQucGFyZW50X25hbWVzID0gJnBhcmVudF9u YW1lOwo+ICsJCWluaXQubnVtX3BhcmVudHMgPSAxOwo+ICsJCWlmIChkc2ktPnBvcnQgPT0gMSkK PiArCQkJaW5pdC5uYW1lID0gcGh5X2Nsb2Nrc1tpXS5kc2kxX25hbWU7Cj4gKwkJZWxzZQo+ICsJ CQlpbml0Lm5hbWUgPSBwaHlfY2xvY2tzW2ldLmRzaTBfbmFtZTsKPiArCQlpbml0Lm9wcyA9ICZj bGtfZml4ZWRfZmFjdG9yX29wczsKPiArCQlpbml0LmZsYWdzID0gQ0xLX0lTX0JBU0lDOwo+ICsK PiArCQljbGsgPSBkZXZtX2Nsa19yZWdpc3RlcihkZXYsICZmaXgtPmh3KTsKPiArCQlpZiAoSVNf RVJSKGNsaykpCj4gKwkJCXJldHVybiBQVFJfRVJSKGNsayk7Cj4gKwo+ICsJCWRzaS0+Y2xrX29u ZWNlbGwuY2xrc1tpXSA9IGNsazsKPiArCX0KPiArCj4gKwlyZXR1cm4gb2ZfY2xrX2FkZF9wcm92 aWRlcihkZXYtPm9mX25vZGUsCj4gKwkJCQkgICBvZl9jbGtfc3JjX29uZWNlbGxfZ2V0LAo+ICsJ CQkJICAgJmRzaS0+Y2xrX29uZWNlbGwpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IHZjNF9kc2lf YmluZChzdHJ1Y3QgZGV2aWNlICpkZXYsIHN0cnVjdCBkZXZpY2UgKm1hc3Rlciwgdm9pZCAqZGF0 YSkKPiArewo+ICsJc3RydWN0IHBsYXRmb3JtX2RldmljZSAqcGRldiA9IHRvX3BsYXRmb3JtX2Rl dmljZShkZXYpOwo+ICsJc3RydWN0IGRybV9kZXZpY2UgKmRybSA9IGRldl9nZXRfZHJ2ZGF0YSht YXN0ZXIpOwo+ICsJc3RydWN0IHZjNF9kZXYgKnZjNCA9IHRvX3ZjNF9kZXYoZHJtKTsKPiArCXN0 cnVjdCB2YzRfZHNpICpkc2k7Cj4gKwlzdHJ1Y3QgdmM0X2RzaV9lbmNvZGVyICp2YzRfZHNpX2Vu Y29kZXI7Cj4gKwljb25zdCBzdHJ1Y3Qgb2ZfZGV2aWNlX2lkICptYXRjaDsKPiArCWRtYV9jYXBf bWFza190IGRtYV9tYXNrOwo+ICsJaW50IHJldDsKPiArCj4gKwlkc2kgPSBkZXZtX2t6YWxsb2Mo ZGV2LCBzaXplb2YoKmRzaSksIEdGUF9LRVJORUwpOwo+ICsJaWYgKCFkc2kpCj4gKwkJcmV0dXJu IC1FTk9NRU07Cj4gKwo+ICsJbWF0Y2ggPSBvZl9tYXRjaF9kZXZpY2UodmM0X2RzaV9kdF9tYXRj aCwgZGV2KTsKPiArCWlmICghbWF0Y2gpCj4gKwkJcmV0dXJuIC1FTk9ERVY7Cj4gKwo+ICsJZHNp LT5wb3J0ID0gKHVpbnRwdHJfdCltYXRjaC0+ZGF0YTsKPiArCj4gKwl2YzRfZHNpX2VuY29kZXIg PSBkZXZtX2t6YWxsb2MoZGV2LCBzaXplb2YoKnZjNF9kc2lfZW5jb2RlciksCj4gKwkJCQkgICAg ICAgR0ZQX0tFUk5FTCk7Cj4gKwlpZiAoIXZjNF9kc2lfZW5jb2RlcikKPiArCQlyZXR1cm4gLUVO T01FTTsKPiArCXZjNF9kc2lfZW5jb2Rlci0+YmFzZS50eXBlID0gVkM0X0VOQ09ERVJfVFlQRV9E U0kxOwo+ICsJdmM0X2RzaV9lbmNvZGVyLT5kc2kgPSBkc2k7Cj4gKwlkc2ktPmVuY29kZXIgPSAm dmM0X2RzaV9lbmNvZGVyLT5iYXNlLmJhc2U7Cj4gKwo+ICsJZHNpLT5wZGV2ID0gcGRldjsKPiAr CWRzaS0+cmVncyA9IHZjNF9pb3JlbWFwX3JlZ3MocGRldiwgMCk7Cj4gKwlpZiAoSVNfRVJSKGRz aS0+cmVncykpCj4gKwkJcmV0dXJuIFBUUl9FUlIoZHNpLT5yZWdzKTsKPiArCj4gKwlpZiAoRFNJ X1BPUlRfUkVBRChJRCkgIT0gRFNJX0lEX1ZBTFVFKSB7Cj4gKwkJZGV2X2VycihkZXYsICJQb3J0 IHJldHVybmVkIDB4JTA4eCBmb3IgSUQgaW5zdGVhZCBvZiAweCUwOHhcbiIsCj4gKwkJCURTSV9Q T1JUX1JFQUQoSUQpLCBEU0lfSURfVkFMVUUpOwo+ICsJCXJldHVybiAtRU5PREVWOwo+ICsJfQo+ ICsKPiArCS8qIERTSTEgaGFzIGEgYnJva2VuIEFYSSBzbGF2ZSB0aGF0IGRvZXNuJ3QgcmVzcG9u ZCB0byB3cml0ZXMKPiArCSAqIGZyb20gdGhlIEFSTS4gIEl0IGRvZXMgaGFuZGxlIHdyaXRlcyBm cm9tIHRoZSBETUEgZW5naW5lLAo+ICsJICogc28gc2V0IHVwIGEgY2hhbm5lbCBmb3IgdGFsa2lu ZyB0byBpdC4KPiArCSAqLwo+ICsJaWYgKGRzaS0+cG9ydCA9PSAxKSB7Cj4gKwkJZHNpLT5yZWdf ZG1hX21lbSA9IGRtYV9hbGxvY19jb2hlcmVudChkZXYsIDQsCj4gKwkJCQkJCSAgICAgICZkc2kt PnJlZ19kbWFfcGFkZHIsCj4gKwkJCQkJCSAgICAgIEdGUF9LRVJORUwpOwo+ICsJCWlmICghZHNp LT5yZWdfZG1hX21lbSkgewo+ICsJCQlEUk1fRVJST1IoIkZhaWxlZCB0byBnZXQgRE1BIG1lbW9y eVxuIik7Cj4gKwkJCXJldHVybiAtRU5PTUVNOwo+ICsJCX0KPiArCj4gKwkJZG1hX2NhcF96ZXJv KGRtYV9tYXNrKTsKPiArCQlkbWFfY2FwX3NldChETUFfTUVNQ1BZLCBkbWFfbWFzayk7Cj4gKwkJ ZHNpLT5yZWdfZG1hX2NoYW4gPSBkbWFfcmVxdWVzdF9jaGFuX2J5X21hc2soJmRtYV9tYXNrKTsK PiArCQlpZiAoSVNfRVJSKGRzaS0+cmVnX2RtYV9jaGFuKSkgewo+ICsJCQlyZXQgPSBQVFJfRVJS KGRzaS0+cmVnX2RtYV9jaGFuKTsKPiArCQkJaWYgKHJldCAhPSAtRVBST0JFX0RFRkVSKQo+ICsJ CQkJRFJNX0VSUk9SKCJGYWlsZWQgdG8gZ2V0IERNQSBjaGFubmVsOiAlZFxuIiwKPiArCQkJCQkg IHJldCk7Cj4gKwkJCXJldHVybiByZXQ7Cj4gKwkJfQo+ICsKPiArCQkvKiBHZXQgdGhlIHBoeXNp Y2FsIGFkZHJlc3Mgb2YgdGhlIGRldmljZSdzIHJlZ2lzdGVycy4gIFRoZQo+ICsJCSAqIHN0cnVj dCByZXNvdXJjZSBmb3IgdGhlIHJlZ3MgZ2l2ZXMgdXMgdGhlIGJ1cyBhZGRyZXNzCj4gKwkJICog aW5zdGVhZC4KPiArCQkgKi8KPiArCQlkc2ktPnJlZ19wYWRkciA9IGJlMzJfdG9fY3B1cChvZl9n ZXRfYWRkcmVzcyhkZXYtPm9mX25vZGUsCj4gKwkJCQkJCQkgICAgIDAsIE5VTEwsIE5VTEwpKTsK PiArCX0KPiArCj4gKwlpbml0X2NvbXBsZXRpb24oJmRzaS0+eGZlcl9jb21wbGV0aW9uKTsKPiAr CS8qIEF0IHN0YXJ0dXAgZW5hYmxlIGVycm9yLXJlcG9ydGluZyBpbnRlcnJ1cHRzIGFuZCBub3Ro aW5nIGVsc2UuICovCj4gKwlEU0lfUE9SVF9XUklURShJTlRfRU4sIERTSTFfSU5URVJSVVBUU19B TFdBWVNfRU5BQkxFRCk7Cj4gKwkvKiBDbGVhciBhbnkgZXhpc3RpbmcgaW50ZXJydXB0IHN0YXRl LiAqLwo+ICsJRFNJX1BPUlRfV1JJVEUoSU5UX1NUQVQsIERTSV9QT1JUX1JFQUQoSU5UX1NUQVQp KTsKPiArCj4gKwlyZXQgPSBkZXZtX3JlcXVlc3RfaXJxKGRldiwgcGxhdGZvcm1fZ2V0X2lycShw ZGV2LCAwKSwKPiArCQkJICAgICAgIHZjNF9kc2lfaXJxX2hhbmRsZXIsIDAsICJ2YzQgZHNpIiwg ZHNpKTsKPiArCWlmIChyZXQpIHsKPiArCQlpZiAocmV0ICE9IC1FUFJPQkVfREVGRVIpCj4gKwkJ CWRldl9lcnIoZGV2LCAiRmFpbGVkIHRvIGdldCBpbnRlcnJ1cHQ6ICVkXG4iLCByZXQpOwo+ICsJ CXJldHVybiByZXQ7Cj4gKwl9Cj4gKwo+ICsJZHNpLT5lc2NhcGVfY2xvY2sgPSBkZXZtX2Nsa19n ZXQoZGV2LCAiZXNjYXBlIik7Cj4gKwlpZiAoSVNfRVJSKGRzaS0+ZXNjYXBlX2Nsb2NrKSkgewo+ ICsJCXJldCA9IFBUUl9FUlIoZHNpLT5lc2NhcGVfY2xvY2spOwo+ICsJCWlmIChyZXQgIT0gLUVQ Uk9CRV9ERUZFUikKPiArCQkJZGV2X2VycihkZXYsICJGYWlsZWQgdG8gZ2V0IGVzY2FwZSBjbG9j azogJWRcbiIsIHJldCk7Cj4gKwkJcmV0dXJuIHJldDsKPiArCX0KPiArCj4gKwlkc2ktPnBsbF9w aHlfY2xvY2sgPSBkZXZtX2Nsa19nZXQoZGV2LCAicGh5Iik7Cj4gKwlpZiAoSVNfRVJSKGRzaS0+ cGxsX3BoeV9jbG9jaykpIHsKPiArCQlyZXQgPSBQVFJfRVJSKGRzaS0+cGxsX3BoeV9jbG9jayk7 Cj4gKwkJaWYgKHJldCAhPSAtRVBST0JFX0RFRkVSKQo+ICsJCQlkZXZfZXJyKGRldiwgIkZhaWxl ZCB0byBnZXQgcGh5IGNsb2NrOiAlZFxuIiwgcmV0KTsKPiArCQlyZXR1cm4gcmV0Owo+ICsJfQo+ ICsKPiArCWRzaS0+cGl4ZWxfY2xvY2sgPSBkZXZtX2Nsa19nZXQoZGV2LCAicGl4ZWwiKTsKPiAr CWlmIChJU19FUlIoZHNpLT5waXhlbF9jbG9jaykpIHsKPiArCQlyZXQgPSBQVFJfRVJSKGRzaS0+ cGl4ZWxfY2xvY2spOwo+ICsJCWlmIChyZXQgIT0gLUVQUk9CRV9ERUZFUikKPiArCQkJZGV2X2Vy cihkZXYsICJGYWlsZWQgdG8gZ2V0IHBpeGVsIGNsb2NrOiAlZFxuIiwgcmV0KTsKPiArCQlyZXR1 cm4gcmV0Owo+ICsJfQo+ICsKPiArCS8qIFRoZSBlc2MgY2xvY2sgcmF0ZSBpcyBzdXBwb3NlZCB0 byBhbHdheXMgYmUgMTAwTWh6LiAqLwo+ICsJcmV0ID0gY2xrX3NldF9yYXRlKGRzaS0+ZXNjYXBl X2Nsb2NrLCAxMDAgKiAxMDAwMDAwKTsKPiArCWlmIChyZXQpIHsKPiArCQlkZXZfZXJyKGRldiwg IkZhaWxlZCB0byBzZXQgZXNjIGNsb2NrOiAlZFxuIiwgcmV0KTsKPiArCQlyZXR1cm4gcmV0Owo+ ICsJfQo+ICsKPiArCXJldCA9IHZjNF9kc2lfaW5pdF9waHlfY2xvY2tzKGRzaSk7Cj4gKwlpZiAo cmV0KQo+ICsJCXJldHVybiByZXQ7Cj4gKwo+ICsJaWYgKGRzaS0+cG9ydCA9PSAxKQo+ICsJCXZj NC0+ZHNpMSA9IGRzaTsKPiArCj4gKwlkcm1fZW5jb2Rlcl9pbml0KGRybSwgZHNpLT5lbmNvZGVy LCAmdmM0X2RzaV9lbmNvZGVyX2Z1bmNzLAo+ICsJCQkgRFJNX01PREVfRU5DT0RFUl9EU0ksIE5V TEwpOwo+ICsJZHJtX2VuY29kZXJfaGVscGVyX2FkZChkc2ktPmVuY29kZXIsICZ2YzRfZHNpX2Vu Y29kZXJfaGVscGVyX2Z1bmNzKTsKPiArCj4gKwlkc2ktPmNvbm5lY3RvciA9IHZjNF9kc2lfY29u bmVjdG9yX2luaXQoZHJtLCBkc2kpOwo+ICsJaWYgKElTX0VSUihkc2ktPmNvbm5lY3RvcikpIHsK PiArCQlyZXQgPSBQVFJfRVJSKGRzaS0+Y29ubmVjdG9yKTsKPiArCQlnb3RvIGVycl9kZXN0cm95 X2VuY29kZXI7Cj4gKwl9Cj4gKwo+ICsJZHNpLT5kc2lfaG9zdC5vcHMgPSAmdmM0X2RzaV9ob3N0 X29wczsKPiArCWRzaS0+ZHNpX2hvc3QuZGV2ID0gZGV2Owo+ICsKPiArCW1pcGlfZHNpX2hvc3Rf cmVnaXN0ZXIoJmRzaS0+ZHNpX2hvc3QpOwo+ICsKPiArCWRldl9zZXRfZHJ2ZGF0YShkZXYsIGRz aSk7Cj4gKwo+ICsJcG1fcnVudGltZV9lbmFibGUoZGV2KTsKPiArCj4gKwlyZXR1cm4gMDsKPiAr Cj4gK2Vycl9kZXN0cm95X2VuY29kZXI6Cj4gKwl2YzRfZHNpX2VuY29kZXJfZGVzdHJveShkc2kt PmVuY29kZXIpOwo+ICsKPiArCXJldHVybiByZXQ7Cj4gK30KPiArCj4gK3N0YXRpYyB2b2lkIHZj NF9kc2lfdW5iaW5kKHN0cnVjdCBkZXZpY2UgKmRldiwgc3RydWN0IGRldmljZSAqbWFzdGVyLAo+ ICsJCQkgICB2b2lkICpkYXRhKQo+ICt7Cj4gKwlzdHJ1Y3QgZHJtX2RldmljZSAqZHJtID0gZGV2 X2dldF9kcnZkYXRhKG1hc3Rlcik7Cj4gKwlzdHJ1Y3QgdmM0X2RldiAqdmM0ID0gdG9fdmM0X2Rl dihkcm0pOwo+ICsJc3RydWN0IHZjNF9kc2kgKmRzaSA9IGRldl9nZXRfZHJ2ZGF0YShkZXYpOwo+ ICsKPiArCXBtX3J1bnRpbWVfZGlzYWJsZShkZXYpOwo+ICsKPiArCXZjNF9kc2lfY29ubmVjdG9y X2Rlc3Ryb3koZHNpLT5jb25uZWN0b3IpOwo+ICsJdmM0X2RzaV9lbmNvZGVyX2Rlc3Ryb3koZHNp LT5lbmNvZGVyKTsKPiArCj4gKwltaXBpX2RzaV9ob3N0X3VucmVnaXN0ZXIoJmRzaS0+ZHNpX2hv c3QpOwo+ICsKPiArCWNsa19kaXNhYmxlX3VucHJlcGFyZShkc2ktPnBsbF9waHlfY2xvY2spOwo+ ICsJY2xrX2Rpc2FibGVfdW5wcmVwYXJlKGRzaS0+ZXNjYXBlX2Nsb2NrKTsKPiArCj4gKwlpZiAo ZHNpLT5wb3J0ID09IDEpCj4gKwkJdmM0LT5kc2kxID0gTlVMTDsKPiArfQo+ICsKPiArc3RhdGlj IGNvbnN0IHN0cnVjdCBjb21wb25lbnRfb3BzIHZjNF9kc2lfb3BzID0gewo+ICsJLmJpbmQgICA9 IHZjNF9kc2lfYmluZCwKPiArCS51bmJpbmQgPSB2YzRfZHNpX3VuYmluZCwKPiArfTsKPiArCj4g K3N0YXRpYyBpbnQgdmM0X2RzaV9kZXZfcHJvYmUoc3RydWN0IHBsYXRmb3JtX2RldmljZSAqcGRl dikKPiArewo+ICsJcmV0dXJuIGNvbXBvbmVudF9hZGQoJnBkZXYtPmRldiwgJnZjNF9kc2lfb3Bz KTsKPiArfQo+ICsKPiArc3RhdGljIGludCB2YzRfZHNpX2Rldl9yZW1vdmUoc3RydWN0IHBsYXRm b3JtX2RldmljZSAqcGRldikKPiArewo+ICsJY29tcG9uZW50X2RlbCgmcGRldi0+ZGV2LCAmdmM0 X2RzaV9vcHMpOwo+ICsJcmV0dXJuIDA7Cj4gK30KPiArCj4gK3N0cnVjdCBwbGF0Zm9ybV9kcml2 ZXIgdmM0X2RzaV9kcml2ZXIgPSB7Cj4gKwkucHJvYmUgPSB2YzRfZHNpX2Rldl9wcm9iZSwKPiAr CS5yZW1vdmUgPSB2YzRfZHNpX2Rldl9yZW1vdmUsCj4gKwkuZHJpdmVyID0gewo+ICsJCS5uYW1l ID0gInZjNF9kc2kiLAo+ICsJCS5vZl9tYXRjaF90YWJsZSA9IHZjNF9kc2lfZHRfbWF0Y2gsCj4g Kwl9LAo+ICt9Owo+IC0tIAo+IDIuMTEuMAo+IAo+IF9fX19fX19fX19fX19fX19fX19fX19fX19f X19fX19fX19fX19fX19fX19fX19fCj4gZHJpLWRldmVsIG1haWxpbmcgbGlzdAo+IGRyaS1kZXZl bEBsaXN0cy5mcmVlZGVza3RvcC5vcmcKPiBodHRwczovL2xpc3RzLmZyZWVkZXNrdG9wLm9yZy9t YWlsbWFuL2xpc3RpbmZvL2RyaS1kZXZlbAoKLS0gCkRhbmllbCBWZXR0ZXIKU29mdHdhcmUgRW5n aW5lZXIsIEludGVsIENvcnBvcmF0aW9uCmh0dHA6Ly9ibG9nLmZmd2xsLmNoCl9fX19fX19fX19f X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fCmRyaS1kZXZlbCBtYWlsaW5nIGxp c3QKZHJpLWRldmVsQGxpc3RzLmZyZWVkZXNrdG9wLm9yZwpodHRwczovL2xpc3RzLmZyZWVkZXNr dG9wLm9yZy9tYWlsbWFuL2xpc3RpbmZvL2RyaS1kZXZlbAo=