From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757978AbcJHJqK (ORCPT ); Sat, 8 Oct 2016 05:46:10 -0400 Received: from mx0b-0016f401.pphosted.com ([67.231.156.173]:57355 "EHLO mx0b-0016f401.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753460AbcJHJqF (ORCPT ); Sat, 8 Oct 2016 05:46:05 -0400 Subject: Re: [PATCH 7/10] mmc: sdhci-xenon: Add support to PHYs of Marvell Xenon SDHC To: Shawn Lin , Gregory CLEMENT , Ulf Hansson , Adrian Hunter , References: <25146173-d98b-f346-b333-4d7466960496@rock-chips.com> CC: Jason Cooper , Andrew Lunn , Sebastian Hesselbarth , Rob Herring , , Thomas Petazzoni , , "Jack(SH) Zhu" , Jimmy Xu , Jisheng Zhang , Nadav Haklai , Ryan Gao , Doug Jones , Shiwu Zhang , Victor Gu , "Wei(SOCP) Liu" , Wilson Ding , Xueping Liu , Hilbert Zhang , Liuliu Zhao , Peng Zhu , Yu Cao , Romain Perier , Yehuda Yitschak , Marcin Wojtas , Hanna Hawa , Kostya Porotchkin , From: Ziji Hu Message-ID: Date: Sat, 8 Oct 2016 17:28:47 +0800 User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:45.0) Gecko/20100101 Thunderbird/45.3.0 MIME-Version: 1.0 In-Reply-To: <25146173-d98b-f346-b333-4d7466960496@rock-chips.com> Content-Type: text/plain; charset="gbk" Content-Transfer-Encoding: 8bit X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:,, definitions=2016-10-08_04:,, signatures=0 X-Proofpoint-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=2 phishscore=0 bulkscore=0 spamscore=0 clxscore=1015 lowpriorityscore=0 impostorscore=0 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1609300000 definitions=main-1610080166 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi Shawn, On 2016/10/8 10:44, Shawn Lin wrote: > ÔÚ 2016/10/7 23:22, Gregory CLEMENT дµÀ: >> From: Ziji Hu >> >> Marvell Xenon eMMC/SD/SDIO Host Controller contains PHY. >> Three types of PHYs are supported. >> >> Add support to multiple types of PHYs init and configuration. >> Add register definitions of PHYs. >> >> Signed-off-by: Hu Ziji >> Reviewed-by: Gregory CLEMENT >> Signed-off-by: Gregory CLEMENT >> --- >> MAINTAINERS | 1 +- >> drivers/mmc/host/Makefile | 2 +- >> drivers/mmc/host/sdhci-xenon-phy.c | 1141 +++++++++++++++++++++++++++++- >> drivers/mmc/host/sdhci-xenon-phy.h | 157 ++++- >> drivers/mmc/host/sdhci-xenon.c | 4 +- >> drivers/mmc/host/sdhci-xenon.h | 17 +- >> 6 files changed, 1321 insertions(+), 1 deletion(-) >> create mode 100644 drivers/mmc/host/sdhci-xenon-phy.c >> create mode 100644 drivers/mmc/host/sdhci-xenon-phy.h >> >> diff --git a/MAINTAINERS b/MAINTAINERS >> index 859420e5dfd3..b5673c2ee5f2 100644 >> --- a/MAINTAINERS >> +++ b/MAINTAINERS >> @@ -7583,6 +7583,7 @@ M: Ziji Hu >> L: linux-mmc@vger.kernel.org >> S: Supported >> F: drivers/mmc/host/sdhci-xenon.* >> +F: drivers/mmc/host/sdhci-xenon-phy.* > > drivers/mmc/host/sdhci-xenon* shoube enough > >> F: Documentation/devicetree/bindings/mmc/marvell,sdhci-xenon.txt >> >> MATROX FRAMEBUFFER DRIVER >> diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile >> index 75eaf743486c..4f2854556ff7 100644 >> --- a/drivers/mmc/host/Makefile >> +++ b/drivers/mmc/host/Makefile >> @@ -82,4 +82,4 @@ ifeq ($(CONFIG_CB710_DEBUG),y) >> endif >> >> obj-$(CONFIG_MMC_SDHCI_XENON) += sdhci-xenon-driver.o >> -sdhci-xenon-driver-y += sdhci-xenon.o >> +sdhci-xenon-driver-y += sdhci-xenon.o sdhci-xenon-phy.o >> diff --git a/drivers/mmc/host/sdhci-xenon-phy.c b/drivers/mmc/host/sdhci-xenon-phy.c >> new file mode 100644 >> index 000000000000..4eb8fea1bec9 >> --- /dev/null >> +++ b/drivers/mmc/host/sdhci-xenon-phy.c > > Well, it's legit to use phy API and move your phy > operations to PHY subsystem. :) > Actually we tried to put the PHY code into Linux PHY framework. But it cannot fit in Linux common PHY framework. Our Xenon SDHC PHY register is a part of Xenon SDHC register set. Besides, during MMC initialization, MMC sequence has to call several PHY functions to complete timing setting. In those PHY setting functions, they have to access SDHC register and know current MMC setting, such as bus width, clock frequency and speed mode. As a result, we have to implement PHY under MMC directory. Thank you. Best regards, Hu Ziji >> @@ -0,0 +1,1141 @@ >> +/* >> + * PHY support for Xenon SDHC >> + * >> + * Copyright (C) 2016 Marvell, All Rights Reserved. >> + * >> + * Author: Hu Ziji >> + * Date: 2016-8-24 >> + * >> + * This program is free software; you can redistribute it and/or >> + * modify it under the terms of the GNU General Public License as >> + * published by the Free Software Foundation version 2. >> + */ >> + >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +#include "sdhci.h" >> +#include "sdhci-pltfm.h" >> +#include "sdhci-xenon.h" >> + >> +static const char * const phy_types[] = { >> + "sdh phy", >> + "emmc 5.0 phy", >> + "emmc 5.1 phy" >> +}; >> + >> +enum phy_type_enum { >> + SDH_PHY, >> + EMMC_5_0_PHY, >> + EMMC_5_1_PHY, >> + NR_PHY_TYPES >> +}; >> + >> +struct soc_pad_ctrl_table { >> + const char *soc; >> + void (*set_soc_pad)(struct sdhci_host *host, >> + unsigned char signal_voltage); >> +}; >> + >> +struct soc_pad_ctrl { >> + /* Register address of SOC PHY PAD ctrl */ >> + void __iomem *reg; >> + /* SOC PHY PAD ctrl type */ >> + enum soc_pad_ctrl_type pad_type; >> + /* SOC specific operation to set SOC PHY PAD */ >> + void (*set_soc_pad)(struct sdhci_host *host, >> + unsigned char signal_voltage); >> +}; >> + >> +static struct xenon_emmc_phy_regs xenon_emmc_5_0_phy_regs = { >> + .timing_adj = EMMC_5_0_PHY_TIMING_ADJUST, >> + .func_ctrl = EMMC_5_0_PHY_FUNC_CONTROL, >> + .pad_ctrl = EMMC_5_0_PHY_PAD_CONTROL, >> + .pad_ctrl2 = EMMC_5_0_PHY_PAD_CONTROL2, >> + .dll_ctrl = EMMC_5_0_PHY_DLL_CONTROL, >> + .logic_timing_adj = EMMC_5_0_PHY_LOGIC_TIMING_ADJUST, >> + .delay_mask = EMMC_5_0_PHY_FIXED_DELAY_MASK, >> + .dll_update = DLL_UPDATE_STROBE_5_0, >> +}; >> + >> +static struct xenon_emmc_phy_regs xenon_emmc_5_1_phy_regs = { >> + .timing_adj = EMMC_PHY_TIMING_ADJUST, >> + .func_ctrl = EMMC_PHY_FUNC_CONTROL, >> + .pad_ctrl = EMMC_PHY_PAD_CONTROL, >> + .pad_ctrl2 = EMMC_PHY_PAD_CONTROL2, >> + .dll_ctrl = EMMC_PHY_DLL_CONTROL, >> + .logic_timing_adj = EMMC_PHY_LOGIC_TIMING_ADJUST, >> + .delay_mask = EMMC_PHY_FIXED_DELAY_MASK, >> + .dll_update = DLL_UPDATE, >> +}; >> + >> +static int xenon_delay_adj_test(struct mmc_card *card); >> + >> +/* >> + * eMMC PHY configuration and operations >> + */ >> +struct emmc_phy_params { >> + bool slow_mode; >> + >> + u8 znr; >> + u8 zpr; >> + >> + /* Nr of consecutive Sampling Points of a Valid Sampling Window */ >> + u8 nr_tun_times; >> + /* Divider for calculating Tuning Step */ >> + u8 tun_step_divider; >> + >> + struct soc_pad_ctrl pad_ctrl; >> +}; >> + >> +static void xenon_emmc_phy_strobe_delay_adj(struct sdhci_host *host, >> + struct mmc_card *card); >> +static int xenon_emmc_phy_fix_sampl_delay_adj(struct sdhci_host *host, >> + struct mmc_card *card); >> +static void xenon_emmc_phy_set(struct sdhci_host *host, >> + unsigned char timing); >> +static void xenon_emmc_set_soc_pad(struct sdhci_host *host, >> + unsigned char signal_voltage); >> + >> +static const struct xenon_phy_ops emmc_phy_ops = { >> + .strobe_delay_adj = xenon_emmc_phy_strobe_delay_adj, >> + .fix_sampl_delay_adj = xenon_emmc_phy_fix_sampl_delay_adj, >> + .phy_set = xenon_emmc_phy_set, >> + .set_soc_pad = xenon_emmc_set_soc_pad, >> +}; >> + >> +static int alloc_emmc_phy(struct sdhci_xenon_priv *priv) >> +{ >> + struct emmc_phy_params *params; >> + >> + params = kzalloc(sizeof(*params), GFP_KERNEL); >> + if (!params) >> + return -ENOMEM; >> + >> + priv->phy_params = params; >> + priv->phy_ops = &emmc_phy_ops; >> + if (priv->phy_type == EMMC_5_0_PHY) >> + priv->emmc_phy_regs = &xenon_emmc_5_0_phy_regs; >> + else >> + priv->emmc_phy_regs = &xenon_emmc_5_1_phy_regs; >> + >> + return 0; >> +} >> + >> +static int xenon_emmc_phy_init(struct sdhci_host *host) >> +{ >> + u32 reg; >> + u32 wait, clock; >> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >> + struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); >> + struct xenon_emmc_phy_regs *phy_regs = priv->emmc_phy_regs; >> + >> + reg = sdhci_readl(host, phy_regs->timing_adj); >> + reg |= PHY_INITIALIZAION; >> + sdhci_writel(host, reg, phy_regs->timing_adj); >> + >> + /* Add duration of FC_SYNC_RST */ >> + wait = ((reg >> FC_SYNC_RST_DURATION_SHIFT) & >> + FC_SYNC_RST_DURATION_MASK); >> + /* Add interval between FC_SYNC_EN and FC_SYNC_RST */ >> + wait += ((reg >> FC_SYNC_RST_EN_DURATION_SHIFT) & >> + FC_SYNC_RST_EN_DURATION_MASK); >> + /* Add duration of asserting FC_SYNC_EN */ >> + wait += ((reg >> FC_SYNC_EN_DURATION_SHIFT) & >> + FC_SYNC_EN_DURATION_MASK); >> + /* Add duration of waiting for PHY */ >> + wait += ((reg >> WAIT_CYCLE_BEFORE_USING_SHIFT) & >> + WAIT_CYCLE_BEFORE_USING_MASK); >> + /* 4 addtional bus clock and 4 AXI bus clock are required */ >> + wait += 8; >> + wait <<= 20; >> + >> + clock = host->clock; >> + if (!clock) >> + /* Use the possibly slowest bus frequency value */ >> + clock = LOWEST_SDCLK_FREQ; >> + /* get the wait time */ >> + wait /= clock; >> + wait++; >> + /* wait for host eMMC PHY init completes */ >> + udelay(wait); >> + >> + reg = sdhci_readl(host, phy_regs->timing_adj); >> + reg &= PHY_INITIALIZAION; >> + if (reg) { >> + dev_err(mmc_dev(host->mmc), "eMMC PHY init cannot complete after %d us\n", >> + wait); >> + return -ETIMEDOUT; >> + } >> + >> + return 0; >> +} >> + >> +#define ARMADA_3700_SOC_PAD_1_8V 0x1 >> +#define ARMADA_3700_SOC_PAD_3_3V 0x0 >> + >> +static void armada_3700_soc_pad_voltage_set(struct sdhci_host *host, >> + unsigned char signal_voltage) >> +{ >> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >> + struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); >> + struct emmc_phy_params *params = priv->phy_params; >> + >> + if (params->pad_ctrl.pad_type == SOC_PAD_FIXED_1_8V) { >> + writel(ARMADA_3700_SOC_PAD_1_8V, params->pad_ctrl.reg); >> + } else if (params->pad_ctrl.pad_type == SOC_PAD_SD) { >> + if (signal_voltage == MMC_SIGNAL_VOLTAGE_180) >> + writel(ARMADA_3700_SOC_PAD_1_8V, params->pad_ctrl.reg); >> + else if (signal_voltage == MMC_SIGNAL_VOLTAGE_330) >> + writel(ARMADA_3700_SOC_PAD_3_3V, params->pad_ctrl.reg); >> + } >> +} >> + >> +static void xenon_emmc_set_soc_pad(struct sdhci_host *host, >> + unsigned char signal_voltage) >> +{ >> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >> + struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); >> + struct emmc_phy_params *params = priv->phy_params; >> + >> + if (!params->pad_ctrl.reg) >> + return; >> + >> + if (params->pad_ctrl.set_soc_pad) >> + params->pad_ctrl.set_soc_pad(host, signal_voltage); >> +} >> + >> +static int emmc_phy_set_fix_sampl_delay(struct sdhci_host *host, >> + unsigned int delay, >> + bool invert, >> + bool delay_90_degree) >> +{ >> + u32 reg; >> + unsigned long flags; >> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >> + struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); >> + struct xenon_emmc_phy_regs *phy_regs = priv->emmc_phy_regs; >> + int ret = 0; >> + >> + spin_lock_irqsave(&host->lock, flags); >> + >> + /* Setup Sampling fix delay */ >> + reg = sdhci_readl(host, SDHC_SLOT_OP_STATUS_CTRL); >> + reg &= ~phy_regs->delay_mask; >> + reg |= delay & phy_regs->delay_mask; >> + sdhci_writel(host, reg, SDHC_SLOT_OP_STATUS_CTRL); >> + >> + if (priv->phy_type == EMMC_5_0_PHY) { >> + /* set 90 degree phase if necessary */ >> + reg &= ~DELAY_90_DEGREE_MASK_EMMC5; >> + reg |= (delay_90_degree << DELAY_90_DEGREE_SHIFT_EMMC5); >> + sdhci_writel(host, reg, SDHC_SLOT_OP_STATUS_CTRL); >> + } >> + >> + /* Disable SDCLK */ >> + reg = sdhci_readl(host, SDHCI_CLOCK_CONTROL); >> + reg &= ~(SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_INT_EN); >> + sdhci_writel(host, reg, SDHCI_CLOCK_CONTROL); >> + >> + udelay(200); >> + >> + if (priv->phy_type == EMMC_5_1_PHY) { >> + /* set 90 degree phase if necessary */ >> + reg = sdhci_readl(host, EMMC_PHY_FUNC_CONTROL); >> + reg &= ~ASYNC_DDRMODE_MASK; >> + reg |= (delay_90_degree << ASYNC_DDRMODE_SHIFT); >> + sdhci_writel(host, reg, EMMC_PHY_FUNC_CONTROL); >> + } >> + >> + /* Setup Inversion of Sampling edge */ >> + reg = sdhci_readl(host, phy_regs->timing_adj); >> + reg &= ~SAMPL_INV_QSP_PHASE_SELECT; >> + reg |= (invert << SAMPL_INV_QSP_PHASE_SELECT_SHIFT); >> + sdhci_writel(host, reg, phy_regs->timing_adj); >> + >> + /* Enable SD internal clock */ >> + ret = enable_xenon_internal_clk(host); >> + if (ret) >> + goto out; >> + >> + /* Enable SDCLK */ >> + reg = sdhci_readl(host, SDHCI_CLOCK_CONTROL); >> + reg |= SDHCI_CLOCK_CARD_EN; >> + sdhci_writel(host, reg, SDHCI_CLOCK_CONTROL); >> + >> + udelay(200); >> + >> + /* >> + * Has to re-initialize eMMC PHY here to active PHY >> + * because later get status cmd will be issued. >> + */ >> + ret = xenon_emmc_phy_init(host); >> + >> +out: >> + spin_unlock_irqrestore(&host->lock, flags); >> + return ret; >> +} >> + >> +static int emmc_phy_do_fix_sampl_delay(struct sdhci_host *host, >> + struct mmc_card *card, >> + unsigned int delay, >> + bool invert, bool quarter) >> +{ >> + int ret; >> + >> + emmc_phy_set_fix_sampl_delay(host, delay, invert, quarter); >> + >> + ret = xenon_delay_adj_test(card); >> + if (ret) { >> + dev_dbg(mmc_dev(host->mmc), >> + "fail when sampling fix delay = %d, phase = %d degree\n", >> + delay, invert * 180 + quarter * 90); >> + return -1; >> + } >> + return 0; >> +} >> + >> +static int xenon_emmc_phy_fix_sampl_delay_adj(struct sdhci_host *host, >> + struct mmc_card *card) >> +{ >> + enum sampl_fix_delay_phase phase; >> + int idx, nr_pair; >> + int ret; >> + unsigned int delay; >> + unsigned int min_delay, max_delay; >> + bool invert, quarter; >> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >> + struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); >> + struct xenon_emmc_phy_regs *phy_regs = priv->emmc_phy_regs; >> + u32 coarse_step, fine_step; >> + const enum sampl_fix_delay_phase delay_edge[] = { >> + PHASE_0_DEGREE, >> + PHASE_180_DEGREE, >> + PHASE_90_DEGREE, >> + PHASE_270_DEGREE >> + }; >> + >> + coarse_step = phy_regs->delay_mask >> 1; >> + fine_step = coarse_step >> 2; >> + >> + nr_pair = ARRAY_SIZE(delay_edge); >> + >> + for (idx = 0; idx < nr_pair; idx++) { >> + phase = delay_edge[idx]; >> + invert = (phase & 0x2) ? true : false; >> + quarter = (phase & 0x1) ? true : false; >> + >> + /* increase delay value to get fix delay */ >> + for (min_delay = 0; >> + min_delay <= phy_regs->delay_mask; >> + min_delay += coarse_step) { >> + ret = emmc_phy_do_fix_sampl_delay(host, card, min_delay, >> + invert, quarter); >> + if (!ret) >> + break; >> + } >> + >> + if (ret) { >> + dev_dbg(mmc_dev(host->mmc), >> + "Fail to set Sampling Fixed Delay with phase = %d degree\n", >> + phase * 90); >> + continue; >> + } >> + >> + for (max_delay = min_delay + fine_step; >> + max_delay < phy_regs->delay_mask; >> + max_delay += fine_step) { >> + ret = emmc_phy_do_fix_sampl_delay(host, card, max_delay, >> + invert, quarter); >> + if (ret) { >> + max_delay -= fine_step; >> + break; >> + } >> + } >> + >> + if (!ret) { >> + ret = emmc_phy_do_fix_sampl_delay(host, card, >> + phy_regs->delay_mask, >> + invert, quarter); >> + if (!ret) >> + max_delay = phy_regs->delay_mask; >> + } >> + >> + /* >> + * Sampling Fixed Delay line window should be large enough, >> + * thus the sampling point (the middle of the window) >> + * can work when environment varies. >> + * However, there is no clear conclusion how large the window >> + * should be. >> + */ >> + if ((max_delay - min_delay) <= >> + EMMC_PHY_FIXED_DELAY_WINDOW_MIN) { >> + dev_info(mmc_dev(host->mmc), >> + "The window size %d with phase = %d degree is too small\n", >> + max_delay - min_delay, phase * 90); >> + continue; >> + } >> + >> + delay = (min_delay + max_delay) / 2; >> + emmc_phy_set_fix_sampl_delay(host, delay, invert, quarter); >> + dev_dbg(mmc_dev(host->mmc), >> + "sampling fix delay = %d with phase = %d degree\n", >> + delay, phase * 90); >> + return 0; >> + } >> + >> + return -EIO; >> +} >> + >> +static int xenon_emmc_phy_enable_dll(struct sdhci_host *host) >> +{ >> + u32 reg; >> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >> + struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); >> + struct xenon_emmc_phy_regs *phy_regs = priv->emmc_phy_regs; >> + u8 timeout; >> + >> + if (WARN_ON(host->clock <= MMC_HIGH_52_MAX_DTR)) >> + return -EINVAL; >> + >> + reg = sdhci_readl(host, phy_regs->dll_ctrl); >> + if (reg & DLL_ENABLE) >> + return 0; >> + >> + /* Enable DLL */ >> + reg = sdhci_readl(host, phy_regs->dll_ctrl); >> + reg |= (DLL_ENABLE | DLL_FAST_LOCK); >> + >> + /* >> + * Set Phase as 90 degree, which is most common value. >> + * Might set another value if necessary. >> + * The granularity is 1 degree. >> + */ >> + reg &= ~((DLL_PHASE_MASK << DLL_PHSEL0_SHIFT) | >> + (DLL_PHASE_MASK << DLL_PHSEL1_SHIFT)); >> + reg |= ((DLL_PHASE_90_DEGREE << DLL_PHSEL0_SHIFT) | >> + (DLL_PHASE_90_DEGREE << DLL_PHSEL1_SHIFT)); >> + >> + reg &= ~DLL_BYPASS_EN; >> + reg |= phy_regs->dll_update; >> + if (priv->phy_type == EMMC_5_1_PHY) >> + reg &= ~DLL_REFCLK_SEL; >> + sdhci_writel(host, reg, phy_regs->dll_ctrl); >> + >> + /* Wait max 32 ms */ >> + timeout = 32; >> + while (!(sdhci_readw(host, SDHC_SLOT_EXT_PRESENT_STATE) & LOCK_STATE)) { >> + if (!timeout) { >> + dev_err(mmc_dev(host->mmc), "Wait for DLL Lock time-out\n"); >> + return -ETIMEDOUT; >> + } >> + timeout--; >> + mdelay(1); >> + } >> + return 0; >> +} >> + >> +static int __emmc_phy_config_tuning(struct sdhci_host *host) >> +{ >> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >> + struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); >> + struct emmc_phy_params *params = priv->phy_params; >> + u32 reg, tuning_step; >> + int ret; >> + unsigned long flags; >> + >> + if (WARN_ON(host->clock <= MMC_HIGH_52_MAX_DTR)) >> + return -EINVAL; >> + >> + spin_lock_irqsave(&host->lock, flags); >> + >> + ret = xenon_emmc_phy_enable_dll(host); >> + if (ret) { >> + spin_unlock_irqrestore(&host->lock, flags); >> + return ret; >> + } >> + >> + reg = sdhci_readl(host, SDHC_SLOT_DLL_CUR_DLY_VAL); >> + tuning_step = reg / params->tun_step_divider; >> + if (unlikely(tuning_step > TUNING_STEP_MASK)) { >> + dev_warn(mmc_dev(host->mmc), >> + "HS200 TUNING_STEP %d is larger than MAX value\n", >> + tuning_step); >> + tuning_step = TUNING_STEP_MASK; >> + } >> + >> + reg = sdhci_readl(host, SDHC_SLOT_OP_STATUS_CTRL); >> + reg &= ~(TUN_CONSECUTIVE_TIMES_MASK << TUN_CONSECUTIVE_TIMES_SHIFT); >> + reg |= (params->nr_tun_times << TUN_CONSECUTIVE_TIMES_SHIFT); >> + reg &= ~(TUNING_STEP_MASK << TUNING_STEP_SHIFT); >> + reg |= (tuning_step << TUNING_STEP_SHIFT); >> + sdhci_writel(host, reg, SDHC_SLOT_OP_STATUS_CTRL); >> + >> + spin_unlock_irqrestore(&host->lock, flags); >> + return 0; >> +} >> + >> +static int xenon_emmc_phy_config_tuning(struct sdhci_host *host) >> +{ >> + return __emmc_phy_config_tuning(host); >> +} >> + >> +static void xenon_emmc_phy_strobe_delay_adj(struct sdhci_host *host, >> + struct mmc_card *card) >> +{ >> + u32 reg; >> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >> + struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); >> + unsigned long flags; >> + >> + if (host->clock <= MMC_HIGH_52_MAX_DTR) >> + return; >> + >> + dev_dbg(mmc_dev(host->mmc), "starts HS400 strobe delay adjustment\n"); >> + >> + spin_lock_irqsave(&host->lock, flags); >> + >> + xenon_emmc_phy_enable_dll(host); >> + >> + /* Enable SDHC Data Strobe */ >> + reg = sdhci_readl(host, SDHC_SLOT_EMMC_CTRL); >> + reg |= ENABLE_DATA_STROBE; >> + sdhci_writel(host, reg, SDHC_SLOT_EMMC_CTRL); >> + >> + /* Set Data Strobe Pull down */ >> + if (priv->phy_type == EMMC_5_0_PHY) { >> + reg = sdhci_readl(host, EMMC_5_0_PHY_PAD_CONTROL); >> + reg |= EMMC5_FC_QSP_PD; >> + reg &= ~EMMC5_FC_QSP_PU; >> + sdhci_writel(host, reg, EMMC_5_0_PHY_PAD_CONTROL); >> + } else { >> + reg = sdhci_readl(host, EMMC_PHY_PAD_CONTROL1); >> + reg |= EMMC5_1_FC_QSP_PD; >> + reg &= ~EMMC5_1_FC_QSP_PU; >> + sdhci_writel(host, reg, EMMC_PHY_PAD_CONTROL1); >> + } >> + spin_unlock_irqrestore(&host->lock, flags); >> +} >> + >> +#define LOGIC_TIMING_VALUE 0x00AA8977 >> + >> +static void xenon_emmc_phy_set(struct sdhci_host *host, >> + unsigned char timing) >> +{ >> + u32 reg; >> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >> + struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); >> + struct emmc_phy_params *params = priv->phy_params; >> + struct xenon_emmc_phy_regs *phy_regs = priv->emmc_phy_regs; >> + struct mmc_card *card = priv->card_candidate; >> + unsigned long flags; >> + >> + dev_dbg(mmc_dev(host->mmc), "eMMC PHY setting starts\n"); >> + >> + spin_lock_irqsave(&host->lock, flags); >> + >> + /* Setup pad, set bit[28] and bits[26:24] */ >> + reg = sdhci_readl(host, phy_regs->pad_ctrl); >> + reg |= (FC_DQ_RECEN | FC_CMD_RECEN | FC_QSP_RECEN | OEN_QSN); >> + /* >> + * All FC_XX_RECEIVCE should be set as CMOS Type >> + */ >> + reg |= FC_ALL_CMOS_RECEIVER; >> + sdhci_writel(host, reg, phy_regs->pad_ctrl); >> + >> + /* Set CMD and DQ Pull Up */ >> + if (priv->phy_type == EMMC_5_0_PHY) { >> + reg = sdhci_readl(host, EMMC_5_0_PHY_PAD_CONTROL); >> + reg |= (EMMC5_FC_CMD_PU | EMMC5_FC_DQ_PU); >> + reg &= ~(EMMC5_FC_CMD_PD | EMMC5_FC_DQ_PD); >> + sdhci_writel(host, reg, EMMC_5_0_PHY_PAD_CONTROL); >> + } else { >> + reg = sdhci_readl(host, EMMC_PHY_PAD_CONTROL1); >> + reg |= (EMMC5_1_FC_CMD_PU | EMMC5_1_FC_DQ_PU); >> + reg &= ~(EMMC5_1_FC_CMD_PD | EMMC5_1_FC_DQ_PD); >> + sdhci_writel(host, reg, EMMC_PHY_PAD_CONTROL1); >> + } >> + >> + if ((timing == MMC_TIMING_LEGACY) || !card) >> + goto phy_init; >> + >> + /* >> + * FIXME: should depends on the specific board timing. >> + */ >> + if ((timing == MMC_TIMING_MMC_HS400) || >> + (timing == MMC_TIMING_MMC_HS200) || >> + (timing == MMC_TIMING_UHS_SDR50) || >> + (timing == MMC_TIMING_UHS_SDR104) || >> + (timing == MMC_TIMING_UHS_DDR50) || >> + (timing == MMC_TIMING_UHS_SDR25) || >> + (timing == MMC_TIMING_MMC_DDR52)) { >> + reg = sdhci_readl(host, phy_regs->timing_adj); >> + reg &= ~OUTPUT_QSN_PHASE_SELECT; >> + sdhci_writel(host, reg, phy_regs->timing_adj); >> + } >> + >> + /* >> + * If SDIO card, set SDIO Mode >> + * Otherwise, clear SDIO Mode and Slow Mode >> + */ >> + if (mmc_card_sdio(card)) { >> + reg = sdhci_readl(host, phy_regs->timing_adj); >> + reg |= TIMING_ADJUST_SDIO_MODE; >> + >> + if ((timing == MMC_TIMING_UHS_SDR25) || >> + (timing == MMC_TIMING_UHS_SDR12) || >> + (timing == MMC_TIMING_SD_HS) || >> + (timing == MMC_TIMING_LEGACY)) >> + reg |= TIMING_ADJUST_SLOW_MODE; >> + >> + sdhci_writel(host, reg, phy_regs->timing_adj); >> + } else { >> + reg = sdhci_readl(host, phy_regs->timing_adj); >> + reg &= ~(TIMING_ADJUST_SDIO_MODE | TIMING_ADJUST_SLOW_MODE); >> + sdhci_writel(host, reg, phy_regs->timing_adj); >> + } >> + >> + if (((timing == MMC_TIMING_UHS_SDR50) || >> + (timing == MMC_TIMING_UHS_SDR25) || >> + (timing == MMC_TIMING_UHS_SDR12) || >> + (timing == MMC_TIMING_SD_HS) || >> + (timing == MMC_TIMING_MMC_HS) || >> + (timing == MMC_TIMING_LEGACY)) && params->slow_mode) { >> + reg = sdhci_readl(host, phy_regs->timing_adj); >> + reg |= TIMING_ADJUST_SLOW_MODE; >> + sdhci_writel(host, reg, phy_regs->timing_adj); >> + } >> + >> + /* >> + * Set preferred ZNR and ZPR value >> + * The ZNR and ZPR value vary between different boards. >> + * Define them both in sdhci-xenon-emmc-phy.h. >> + */ >> + reg = sdhci_readl(host, phy_regs->pad_ctrl2); >> + reg &= ~((ZNR_MASK << ZNR_SHIFT) | ZPR_MASK); >> + reg |= ((params->znr << ZNR_SHIFT) | params->zpr); >> + sdhci_writel(host, reg, phy_regs->pad_ctrl2); >> + >> + /* >> + * When setting EMMC_PHY_FUNC_CONTROL register, >> + * SD clock should be disabled >> + */ >> + reg = sdhci_readl(host, SDHCI_CLOCK_CONTROL); >> + reg &= ~SDHCI_CLOCK_CARD_EN; >> + sdhci_writew(host, reg, SDHCI_CLOCK_CONTROL); >> + >> + if ((timing == MMC_TIMING_UHS_DDR50) || >> + (timing == MMC_TIMING_MMC_HS400) || >> + (timing == MMC_TIMING_MMC_DDR52)) { >> + reg = sdhci_readl(host, phy_regs->func_ctrl); >> + reg |= (DQ_DDR_MODE_MASK << DQ_DDR_MODE_SHIFT) | CMD_DDR_MODE; >> + sdhci_writel(host, reg, phy_regs->func_ctrl); >> + } >> + >> + if (timing == MMC_TIMING_MMC_HS400) { >> + reg = sdhci_readl(host, phy_regs->func_ctrl); >> + reg &= ~DQ_ASYNC_MODE; >> + sdhci_writel(host, reg, phy_regs->func_ctrl); >> + } >> + >> + /* Enable bus clock */ >> + reg = sdhci_readl(host, SDHCI_CLOCK_CONTROL); >> + reg |= SDHCI_CLOCK_CARD_EN; >> + sdhci_writew(host, reg, SDHCI_CLOCK_CONTROL); >> + >> + if (timing == MMC_TIMING_MMC_HS400) >> + /* Hardware team recommend a value for HS400 */ >> + sdhci_writel(host, LOGIC_TIMING_VALUE, >> + phy_regs->logic_timing_adj); >> + >> +phy_init: >> + xenon_emmc_phy_init(host); >> + >> + spin_unlock_irqrestore(&host->lock, flags); >> + >> + dev_dbg(mmc_dev(host->mmc), "eMMC PHY setting completes\n"); >> +} >> + >> +static int get_dt_pad_ctrl_data(struct sdhci_host *host, >> + struct device_node *np, >> + struct emmc_phy_params *params) >> +{ >> + int ret = 0; >> + const char *name; >> + struct resource iomem; >> + >> + if (of_device_is_compatible(np, "marvell,armada-3700-sdhci")) >> + params->pad_ctrl.set_soc_pad = armada_3700_soc_pad_voltage_set; >> + else >> + return 0; >> + >> + if (of_address_to_resource(np, 1, &iomem)) { >> + dev_err(mmc_dev(host->mmc), "Unable to find SOC PAD ctrl register address for %s\n", >> + np->name); >> + return -EINVAL; >> + } >> + >> + params->pad_ctrl.reg = devm_ioremap_resource(mmc_dev(host->mmc), >> + &iomem); >> + if (IS_ERR(params->pad_ctrl.reg)) { >> + dev_err(mmc_dev(host->mmc), "Unable to get SOC PHY PAD ctrl regiser for %s\n", >> + np->name); >> + return PTR_ERR(params->pad_ctrl.reg); >> + } >> + >> + ret = of_property_read_string(np, "xenon,pad-type", &name); >> + if (ret) { >> + dev_err(mmc_dev(host->mmc), "Unable to determine SOC PHY PAD ctrl type\n"); >> + return ret; >> + } >> + if (!strcmp(name, "sd")) { >> + params->pad_ctrl.pad_type = SOC_PAD_SD; >> + } else if (!strcmp(name, "fixed-1-8v")) { >> + params->pad_ctrl.pad_type = SOC_PAD_FIXED_1_8V; >> + } else { >> + dev_err(mmc_dev(host->mmc), "Unsupported SOC PHY PAD ctrl type %s\n", >> + name); >> + return -EINVAL; >> + } >> + >> + return ret; >> +} >> + >> +static int emmc_phy_parse_param_dt(struct sdhci_host *host, >> + struct device_node *np, >> + struct emmc_phy_params *params) >> +{ >> + u32 value; >> + >> + if (of_property_read_bool(np, "xenon,phy-slow-mode")) >> + params->slow_mode = true; >> + else >> + params->slow_mode = false; >> + >> + if (!of_property_read_u32(np, "xenon,phy-znr", &value)) >> + params->znr = value & ZNR_MASK; >> + else >> + params->znr = ZNR_DEF_VALUE; >> + >> + if (!of_property_read_u32(np, "xenon,phy-zpr", &value)) >> + params->zpr = value & ZPR_MASK; >> + else >> + params->zpr = ZPR_DEF_VALUE; >> + >> + if (!of_property_read_u32(np, "xenon,phy-nr-tun-times", &value)) >> + params->nr_tun_times = value & TUN_CONSECUTIVE_TIMES_MASK; >> + else >> + params->nr_tun_times = TUN_CONSECUTIVE_TIMES; >> + >> + if (!of_property_read_u32(np, "xenon,phy-tun-step-divider", &value)) >> + params->tun_step_divider = value & 0xFF; >> + else >> + params->tun_step_divider = TUNING_STEP_DIVIDER; >> + >> + return get_dt_pad_ctrl_data(host, np, params); >> +} >> + >> +/* >> + * SDH PHY configuration and operations >> + */ >> +static int xenon_sdh_phy_set_fix_sampl_delay(struct sdhci_host *host, >> + unsigned int delay, bool invert) >> +{ >> + u32 reg; >> + unsigned long flags; >> + int ret; >> + >> + if (invert) >> + invert = 0x1; >> + else >> + invert = 0x0; >> + >> + spin_lock_irqsave(&host->lock, flags); >> + >> + /* Disable SDCLK */ >> + reg = sdhci_readl(host, SDHCI_CLOCK_CONTROL); >> + reg &= ~(SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_INT_EN); >> + sdhci_writel(host, reg, SDHCI_CLOCK_CONTROL); >> + >> + udelay(200); >> + >> + /* Setup Sampling fix delay */ >> + reg = sdhci_readl(host, SDHC_SLOT_OP_STATUS_CTRL); >> + reg &= ~(SDH_PHY_FIXED_DELAY_MASK | >> + (0x1 << FORCE_SEL_INVERSE_CLK_SHIFT)); >> + reg |= ((delay & SDH_PHY_FIXED_DELAY_MASK) | >> + (invert << FORCE_SEL_INVERSE_CLK_SHIFT)); >> + sdhci_writel(host, reg, SDHC_SLOT_OP_STATUS_CTRL); >> + >> + /* Enable SD internal clock */ >> + ret = enable_xenon_internal_clk(host); >> + >> + /* Enable SDCLK */ >> + reg = sdhci_readl(host, SDHCI_CLOCK_CONTROL); >> + reg |= SDHCI_CLOCK_CARD_EN; >> + sdhci_writel(host, reg, SDHCI_CLOCK_CONTROL); >> + >> + udelay(200); >> + >> + spin_unlock_irqrestore(&host->lock, flags); >> + return ret; >> +} >> + >> +static int sdh_phy_do_fix_sampl_delay(struct sdhci_host *host, >> + struct mmc_card *card, >> + unsigned int delay, bool invert) >> +{ >> + int ret; >> + >> + xenon_sdh_phy_set_fix_sampl_delay(host, delay, invert); >> + >> + ret = xenon_delay_adj_test(card); >> + if (ret) { >> + dev_dbg(mmc_dev(host->mmc), >> + "fail when sampling fix delay = %d, phase = %d degree\n", >> + delay, invert * 180); >> + return -1; >> + } >> + return 0; >> +} >> + >> +#define SDH_PHY_COARSE_FIX_DELAY (SDH_PHY_FIXED_DELAY_MASK / 2) >> +#define SDH_PHY_FINE_FIX_DELAY (SDH_PHY_COARSE_FIX_DELAY / 4) >> + >> +static int xenon_sdh_phy_fix_sampl_delay_adj(struct sdhci_host *host, >> + struct mmc_card *card) >> +{ >> + u32 reg; >> + bool dll_enable = false; >> + unsigned int min_delay, max_delay, delay; >> + const bool sampl_edge[] = { >> + false, >> + true, >> + }; >> + int i, nr; >> + int ret; >> + >> + if (host->clock > HIGH_SPEED_MAX_DTR) { >> + /* Enable DLL when SDCLK is higher than 50MHz */ >> + reg = sdhci_readl(host, SDH_PHY_SLOT_DLL_CTRL); >> + if (!(reg & SDH_PHY_ENABLE_DLL)) { >> + reg |= (SDH_PHY_ENABLE_DLL | SDH_PHY_FAST_LOCK_EN); >> + sdhci_writel(host, reg, SDH_PHY_SLOT_DLL_CTRL); >> + mdelay(1); >> + >> + reg = sdhci_readl(host, SDH_PHY_SLOT_DLL_PHASE_SEL); >> + reg |= SDH_PHY_DLL_UPDATE_TUNING; >> + sdhci_writel(host, reg, SDH_PHY_SLOT_DLL_PHASE_SEL); >> + } >> + dll_enable = true; >> + } >> + >> + nr = dll_enable ? ARRAY_SIZE(sampl_edge) : 1; >> + for (i = 0; i < nr; i++) { >> + for (min_delay = 0; min_delay <= SDH_PHY_FIXED_DELAY_MASK; >> + min_delay += SDH_PHY_COARSE_FIX_DELAY) { >> + ret = sdh_phy_do_fix_sampl_delay(host, card, min_delay, >> + sampl_edge[i]); >> + if (!ret) >> + break; >> + } >> + >> + if (ret) { >> + dev_dbg(mmc_dev(host->mmc), >> + "Fail to set Fixed Sampling Delay with %s edge\n", >> + sampl_edge[i] ? "negative" : "positive"); >> + continue; >> + } >> + >> + for (max_delay = min_delay + SDH_PHY_FINE_FIX_DELAY; >> + max_delay < SDH_PHY_FIXED_DELAY_MASK; >> + max_delay += SDH_PHY_FINE_FIX_DELAY) { >> + ret = sdh_phy_do_fix_sampl_delay(host, card, max_delay, >> + sampl_edge[i]); >> + if (ret) { >> + max_delay -= SDH_PHY_FINE_FIX_DELAY; >> + break; >> + } >> + } >> + >> + if (!ret) { >> + delay = SDH_PHY_FIXED_DELAY_MASK; >> + ret = sdh_phy_do_fix_sampl_delay(host, card, delay, >> + sampl_edge[i]); >> + if (!ret) >> + max_delay = SDH_PHY_FIXED_DELAY_MASK; >> + } >> + >> + if ((max_delay - min_delay) <= SDH_PHY_FIXED_DELAY_WINDOW_MIN) { >> + dev_info(mmc_dev(host->mmc), >> + "The window size %d with %s edge is too small\n", >> + max_delay - min_delay, >> + sampl_edge[i] ? "negative" : "positive"); >> + continue; >> + } >> + >> + delay = (min_delay + max_delay) / 2; >> + xenon_sdh_phy_set_fix_sampl_delay(host, delay, sampl_edge[i]); >> + dev_dbg(mmc_dev(host->mmc), "sampling fix delay = %d with %s edge\n", >> + delay, sampl_edge[i] ? "negative" : "positive"); >> + return 0; >> + } >> + return -EIO; >> +} >> + >> +static const struct xenon_phy_ops sdh_phy_ops = { >> + .fix_sampl_delay_adj = xenon_sdh_phy_fix_sampl_delay_adj, >> +}; >> + >> +static int alloc_sdh_phy(struct sdhci_xenon_priv *priv) >> +{ >> + priv->phy_params = NULL; >> + priv->phy_ops = &sdh_phy_ops; >> + return 0; >> +} >> + >> +/* >> + * Common functions for all PHYs >> + */ >> +void xenon_soc_pad_ctrl(struct sdhci_host *host, >> + unsigned char signal_voltage) >> +{ >> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >> + struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); >> + >> + if (priv->phy_ops->set_soc_pad) >> + priv->phy_ops->set_soc_pad(host, signal_voltage); >> +} >> + >> +static int __xenon_emmc_delay_adj_test(struct mmc_card *card) >> +{ >> + int err; >> + u8 *ext_csd = NULL; >> + >> + err = mmc_get_ext_csd(card, &ext_csd); >> + kfree(ext_csd); >> + >> + return err; >> +} >> + >> +static int __xenon_sdio_delay_adj_test(struct mmc_card *card) >> +{ >> + struct mmc_command cmd = {0}; >> + int err; >> + >> + cmd.opcode = SD_IO_RW_DIRECT; >> + cmd.flags = MMC_RSP_R5 | MMC_CMD_AC; >> + >> + err = mmc_wait_for_cmd(card->host, &cmd, 0); >> + if (err) >> + return err; >> + >> + if (cmd.resp[0] & R5_ERROR) >> + return -EIO; >> + if (cmd.resp[0] & R5_FUNCTION_NUMBER) >> + return -EINVAL; >> + if (cmd.resp[0] & R5_OUT_OF_RANGE) >> + return -ERANGE; >> + return 0; >> +} >> + >> +static int __xenon_sd_delay_adj_test(struct mmc_card *card) >> +{ >> + struct mmc_command cmd = {0}; >> + int err; >> + >> + cmd.opcode = MMC_SEND_STATUS; >> + cmd.arg = card->rca << 16; >> + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; >> + >> + err = mmc_wait_for_cmd(card->host, &cmd, 0); >> + return err; >> +} >> + >> +static int xenon_delay_adj_test(struct mmc_card *card) >> +{ >> + WARN_ON(!card); >> + WARN_ON(!card->host); >> + >> + if (mmc_card_mmc(card)) >> + return __xenon_emmc_delay_adj_test(card); >> + else if (mmc_card_sd(card)) >> + return __xenon_sd_delay_adj_test(card); >> + else if (mmc_card_sdio(card)) >> + return __xenon_sdio_delay_adj_test(card); >> + else >> + return -EINVAL; >> +} >> + >> +static void xenon_phy_set(struct sdhci_host *host, unsigned char timing) >> +{ >> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >> + struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); >> + >> + if (priv->phy_ops->phy_set) >> + priv->phy_ops->phy_set(host, timing); >> +} >> + >> +static void xenon_hs400_strobe_delay_adj(struct sdhci_host *host, >> + struct mmc_card *card) >> +{ >> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >> + struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); >> + >> + if (WARN_ON(!mmc_card_hs400(card))) >> + return; >> + >> + /* Enable the DLL to automatically adjust HS400 strobe delay. >> + */ >> + if (priv->phy_ops->strobe_delay_adj) >> + priv->phy_ops->strobe_delay_adj(host, card); >> +} >> + >> +static int xenon_fix_sampl_delay_adj(struct sdhci_host *host, >> + struct mmc_card *card) >> +{ >> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >> + struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); >> + >> + if (priv->phy_ops->fix_sampl_delay_adj) >> + return priv->phy_ops->fix_sampl_delay_adj(host, card); >> + >> + return 0; >> +} >> + >> +/* >> + * xenon_delay_adj should not be called inside IRQ context, >> + * either Hard IRQ or Softirq. >> + */ >> +static int xenon_hs_delay_adj(struct sdhci_host *host, >> + struct mmc_card *card) >> +{ >> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >> + struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); >> + int ret = 0; >> + >> + if (WARN_ON(host->clock <= DEFAULT_SDCLK_FREQ)) >> + return -EINVAL; >> + >> + if (mmc_card_hs400(card)) { >> + xenon_hs400_strobe_delay_adj(host, card); >> + return 0; >> + } >> + >> + if (((priv->phy_type == EMMC_5_1_PHY) || >> + (priv->phy_type == EMMC_5_0_PHY)) && >> + (mmc_card_hs200(card) || >> + (host->timing == MMC_TIMING_UHS_SDR104))) { >> + ret = xenon_emmc_phy_config_tuning(host); >> + if (!ret) >> + return 0; >> + } >> + >> + ret = xenon_fix_sampl_delay_adj(host, card); >> + if (ret) >> + dev_err(mmc_dev(host->mmc), "fails sampling fixed delay adjustment\n"); >> + return ret; >> +} >> + >> +int xenon_phy_adj(struct sdhci_host *host, struct mmc_ios *ios) >> +{ >> + struct mmc_host *mmc = host->mmc; >> + struct mmc_card *card; >> + int ret = 0; >> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >> + struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); >> + >> + if (!host->clock) { >> + priv->clock = 0; >> + return 0; >> + } >> + >> + /* >> + * The timing, frequency or bus width is changed, >> + * better to set eMMC PHY based on current setting >> + * and adjust Xenon SDHC delay. >> + */ >> + if ((host->clock == priv->clock) && >> + (ios->bus_width == priv->bus_width) && >> + (ios->timing == priv->timing)) >> + return 0; >> + >> + xenon_phy_set(host, ios->timing); >> + >> + /* Update the record */ >> + priv->bus_width = ios->bus_width; >> + /* Temp stage from HS200 to HS400 */ >> + if (((priv->timing == MMC_TIMING_MMC_HS200) && >> + (ios->timing == MMC_TIMING_MMC_HS)) || >> + ((ios->timing == MMC_TIMING_MMC_HS) && >> + (priv->clock > host->clock))) { >> + priv->timing = ios->timing; >> + priv->clock = host->clock; >> + return 0; >> + } >> + priv->timing = ios->timing; >> + priv->clock = host->clock; >> + >> + /* Legacy mode is a special case */ >> + if (ios->timing == MMC_TIMING_LEGACY) >> + return 0; >> + >> + card = priv->card_candidate; >> + if (unlikely(!card)) { >> + dev_warn(mmc_dev(mmc), "card is not present\n"); >> + return -EINVAL; >> + } >> + >> + if (host->clock > DEFAULT_SDCLK_FREQ) >> + ret = xenon_hs_delay_adj(host, card); >> + return ret; >> +} >> + >> +static int add_xenon_phy(struct device_node *np, struct sdhci_host *host, >> + const char *phy_name) >> +{ >> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >> + struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); >> + int i, ret; >> + >> + for (i = 0; i < NR_PHY_TYPES; i++) { >> + if (!strcmp(phy_name, phy_types[i])) { >> + priv->phy_type = i; >> + break; >> + } >> + } >> + if (i == NR_PHY_TYPES) { >> + dev_err(mmc_dev(host->mmc), >> + "Unable to determine PHY name %s. Use default eMMC 5.1 PHY\n", >> + phy_name); >> + priv->phy_type = EMMC_5_1_PHY; >> + } >> + >> + if (priv->phy_type == SDH_PHY) { >> + return alloc_sdh_phy(priv); >> + } else if ((priv->phy_type == EMMC_5_0_PHY) || >> + (priv->phy_type == EMMC_5_1_PHY)) { >> + ret = alloc_emmc_phy(priv); >> + if (ret) >> + return ret; >> + return emmc_phy_parse_param_dt(host, np, priv->phy_params); >> + } >> + >> + return -EINVAL; >> +} >> + >> +int xenon_phy_parse_dt(struct device_node *np, struct sdhci_host *host) >> +{ >> + const char *phy_type = NULL; >> + >> + if (!of_property_read_string(np, "xenon,phy-type", &phy_type)) >> + return add_xenon_phy(np, host, phy_type); >> + >> + dev_err(mmc_dev(host->mmc), "Fail to get Xenon PHY type. Use default eMMC 5.1 PHY\n"); >> + return add_xenon_phy(np, host, "emmc 5.1 phy"); >> +} >> diff --git a/drivers/mmc/host/sdhci-xenon-phy.h b/drivers/mmc/host/sdhci-xenon-phy.h >> new file mode 100644 >> index 000000000000..4373c71d3b7b >> --- /dev/null >> +++ b/drivers/mmc/host/sdhci-xenon-phy.h >> @@ -0,0 +1,157 @@ >> +/* linux/drivers/mmc/host/sdhci-xenon-phy.h >> + * >> + * Author: Hu Ziji >> + * Date: 2016-8-24 >> + * >> + * Copyright (C) 2016 Marvell, All Rights Reserved. >> + * >> + * This program is free software; you can redistribute it and/or modify >> + * it under the terms of the GNU General Public License as published by >> + * the Free Software Foundation; either version 2 of the License, or (at >> + * your option) any later version. >> + */ >> +#ifndef SDHCI_XENON_PHY_H_ >> +#define SDHCI_XENON_PHY_H_ >> + >> +#include >> +#include "sdhci.h" >> + >> +/* Register base for eMMC PHY 5.0 Version */ >> +#define EMMC_5_0_PHY_REG_BASE 0x0160 >> +/* Register base for eMMC PHY 5.1 Version */ >> +#define EMMC_PHY_REG_BASE 0x0170 >> + >> +#define EMMC_PHY_TIMING_ADJUST EMMC_PHY_REG_BASE >> +#define EMMC_5_0_PHY_TIMING_ADJUST EMMC_5_0_PHY_REG_BASE >> +#define TIMING_ADJUST_SLOW_MODE BIT(29) >> +#define TIMING_ADJUST_SDIO_MODE BIT(28) >> +#define OUTPUT_QSN_PHASE_SELECT BIT(17) >> +#define SAMPL_INV_QSP_PHASE_SELECT BIT(18) >> +#define SAMPL_INV_QSP_PHASE_SELECT_SHIFT 18 >> +#define PHY_INITIALIZAION BIT(31) >> +#define WAIT_CYCLE_BEFORE_USING_MASK 0xF >> +#define WAIT_CYCLE_BEFORE_USING_SHIFT 12 >> +#define FC_SYNC_EN_DURATION_MASK 0xF >> +#define FC_SYNC_EN_DURATION_SHIFT 8 >> +#define FC_SYNC_RST_EN_DURATION_MASK 0xF >> +#define FC_SYNC_RST_EN_DURATION_SHIFT 4 >> +#define FC_SYNC_RST_DURATION_MASK 0xF >> +#define FC_SYNC_RST_DURATION_SHIFT 0 >> + >> +#define EMMC_PHY_FUNC_CONTROL (EMMC_PHY_REG_BASE + 0x4) >> +#define EMMC_5_0_PHY_FUNC_CONTROL (EMMC_5_0_PHY_REG_BASE + 0x4) >> +#define ASYNC_DDRMODE_MASK BIT(23) >> +#define ASYNC_DDRMODE_SHIFT 23 >> +#define CMD_DDR_MODE BIT(16) >> +#define DQ_DDR_MODE_SHIFT 8 >> +#define DQ_DDR_MODE_MASK 0xFF >> +#define DQ_ASYNC_MODE BIT(4) >> + >> +#define EMMC_PHY_PAD_CONTROL (EMMC_PHY_REG_BASE + 0x8) >> +#define EMMC_5_0_PHY_PAD_CONTROL (EMMC_5_0_PHY_REG_BASE + 0x8) >> +#define REC_EN_SHIFT 24 >> +#define REC_EN_MASK 0xF >> +#define FC_DQ_RECEN BIT(24) >> +#define FC_CMD_RECEN BIT(25) >> +#define FC_QSP_RECEN BIT(26) >> +#define FC_QSN_RECEN BIT(27) >> +#define OEN_QSN BIT(28) >> +#define AUTO_RECEN_CTRL BIT(30) >> +#define FC_ALL_CMOS_RECEIVER 0xF000 >> + >> +#define EMMC5_FC_QSP_PD BIT(18) >> +#define EMMC5_FC_QSP_PU BIT(22) >> +#define EMMC5_FC_CMD_PD BIT(17) >> +#define EMMC5_FC_CMD_PU BIT(21) >> +#define EMMC5_FC_DQ_PD BIT(16) >> +#define EMMC5_FC_DQ_PU BIT(20) >> + >> +#define EMMC_PHY_PAD_CONTROL1 (EMMC_PHY_REG_BASE + 0xC) >> +#define EMMC5_1_FC_QSP_PD BIT(9) >> +#define EMMC5_1_FC_QSP_PU BIT(25) >> +#define EMMC5_1_FC_CMD_PD BIT(8) >> +#define EMMC5_1_FC_CMD_PU BIT(24) >> +#define EMMC5_1_FC_DQ_PD 0xFF >> +#define EMMC5_1_FC_DQ_PU (0xFF << 16) >> + >> +#define EMMC_PHY_PAD_CONTROL2 (EMMC_PHY_REG_BASE + 0x10) >> +#define EMMC_5_0_PHY_PAD_CONTROL2 (EMMC_5_0_PHY_REG_BASE + 0xC) >> +#define ZNR_MASK 0x1F >> +#define ZNR_SHIFT 8 >> +#define ZPR_MASK 0x1F >> +/* Perferred ZNR and ZPR value vary between different boards. >> + * The specific ZNR and ZPR value should be defined here >> + * according to board actual timing. >> + */ >> +#define ZNR_DEF_VALUE 0xF >> +#define ZPR_DEF_VALUE 0xF >> + >> +#define EMMC_PHY_DLL_CONTROL (EMMC_PHY_REG_BASE + 0x14) >> +#define EMMC_5_0_PHY_DLL_CONTROL (EMMC_5_0_PHY_REG_BASE + 0x10) >> +#define DLL_ENABLE BIT(31) >> +#define DLL_UPDATE_STROBE_5_0 BIT(30) >> +#define DLL_REFCLK_SEL BIT(30) >> +#define DLL_UPDATE BIT(23) >> +#define DLL_PHSEL1_SHIFT 24 >> +#define DLL_PHSEL0_SHIFT 16 >> +#define DLL_PHASE_MASK 0x3F >> +#define DLL_PHASE_90_DEGREE 0x1F >> +#define DLL_FAST_LOCK BIT(5) >> +#define DLL_GAIN2X BIT(3) >> +#define DLL_BYPASS_EN BIT(0) >> + >> +#define EMMC_5_0_PHY_LOGIC_TIMING_ADJUST (EMMC_5_0_PHY_REG_BASE + 0x14) >> +#define EMMC_PHY_LOGIC_TIMING_ADJUST (EMMC_PHY_REG_BASE + 0x18) >> + >> +enum sampl_fix_delay_phase { >> + PHASE_0_DEGREE = 0x0, >> + PHASE_90_DEGREE = 0x1, >> + PHASE_180_DEGREE = 0x2, >> + PHASE_270_DEGREE = 0x3, >> +}; >> + >> +#define SDH_PHY_SLOT_DLL_CTRL (0x0138) >> +#define SDH_PHY_ENABLE_DLL BIT(1) >> +#define SDH_PHY_FAST_LOCK_EN BIT(5) >> + >> +#define SDH_PHY_SLOT_DLL_PHASE_SEL (0x013C) >> +#define SDH_PHY_DLL_UPDATE_TUNING BIT(15) >> + >> +enum soc_pad_ctrl_type { >> + SOC_PAD_SD, >> + SOC_PAD_FIXED_1_8V, >> +}; >> + >> +/* >> + * List offset of PHY registers and some special register values >> + * in eMMC PHY 5.0 or eMMC PHY 5.1 >> + */ >> +struct xenon_emmc_phy_regs { >> + /* Offset of Timing Adjust register */ >> + u16 timing_adj; >> + /* Offset of Func Control register */ >> + u16 func_ctrl; >> + /* Offset of Pad Control register */ >> + u16 pad_ctrl; >> + /* Offset of Pad Control register */ >> + u16 pad_ctrl2; >> + /* Offset of DLL Control register */ >> + u16 dll_ctrl; >> + /* Offset of Logic Timing Adjust register */ >> + u16 logic_timing_adj; >> + /* Max value of eMMC Fixed Sampling Delay */ >> + u32 delay_mask; >> + /* DLL Update Enable bit */ >> + u32 dll_update; >> +}; >> + >> +struct xenon_phy_ops { >> + void (*strobe_delay_adj)(struct sdhci_host *host, >> + struct mmc_card *card); >> + int (*fix_sampl_delay_adj)(struct sdhci_host *host, >> + struct mmc_card *card); >> + void (*phy_set)(struct sdhci_host *host, unsigned char timing); >> + void (*set_soc_pad)(struct sdhci_host *host, >> + unsigned char signal_voltage); >> +}; >> +#endif >> diff --git a/drivers/mmc/host/sdhci-xenon.c b/drivers/mmc/host/sdhci-xenon.c >> index 03ba183494d3..4d7d871544fc 100644 >> --- a/drivers/mmc/host/sdhci-xenon.c >> +++ b/drivers/mmc/host/sdhci-xenon.c >> @@ -224,6 +224,7 @@ static void xenon_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) >> spin_unlock_irqrestore(&host->lock, flags); >> >> sdhci_set_ios(mmc, ios); >> + xenon_phy_adj(host, ios); >> >> if (host->clock > DEFAULT_SDCLK_FREQ) { >> spin_lock_irqsave(&host->lock, flags); >> @@ -309,6 +310,8 @@ static int xenon_start_signal_voltage_switch(struct mmc_host *mmc, >> */ >> enable_xenon_internal_clk(host); >> >> + xenon_soc_pad_ctrl(host, ios->signal_voltage); >> + >> if (priv->card_candidate) { >> if (mmc_card_mmc(priv->card_candidate)) >> return xenon_emmc_signal_voltage_switch(mmc, ios); >> @@ -453,6 +456,7 @@ static int xenon_probe_dt(struct platform_device *pdev) >> sdhci_writel(host, reg, SDHC_SYS_EXT_OP_CTRL); >> } >> >> + err = xenon_phy_parse_dt(np, host); >> return err; >> } >> >> diff --git a/drivers/mmc/host/sdhci-xenon.h b/drivers/mmc/host/sdhci-xenon.h >> index c2370493fbe8..06e5261a563c 100644 >> --- a/drivers/mmc/host/sdhci-xenon.h >> +++ b/drivers/mmc/host/sdhci-xenon.h >> @@ -15,6 +15,7 @@ >> #include >> #include >> #include "sdhci.h" >> +#include "sdhci-xenon-phy.h" >> >> /* Register Offset of SD Host Controller SOCP self-defined register */ >> #define SDHC_SYS_CFG_INFO 0x0104 >> @@ -76,6 +77,7 @@ >> #define MMC_TIMING_FAKE 0xFF >> >> #define DEFAULT_SDCLK_FREQ (400000) >> +#define LOWEST_SDCLK_FREQ (100000) >> >> /* Xenon specific Mode Select value */ >> #define XENON_SDHCI_CTRL_HS200 0x5 >> @@ -97,6 +99,15 @@ struct sdhci_xenon_priv { >> /* Slot idx */ >> u8 slot_idx; >> >> + int phy_type; >> + /* >> + * Contains board-specific PHY parameters >> + * passed from device tree. >> + */ >> + void *phy_params; >> + const struct xenon_phy_ops *phy_ops; >> + struct xenon_emmc_phy_regs *emmc_phy_regs; >> + >> /* >> * When initializing card, Xenon has to determine card type and >> * adjust Sampling Fixed delay. >> @@ -131,4 +142,10 @@ static inline int enable_xenon_internal_clk(struct sdhci_host *host) >> >> return 0; >> } >> + >> +int xenon_phy_adj(struct sdhci_host *host, struct mmc_ios *ios); >> +int xenon_phy_parse_dt(struct device_node *np, >> + struct sdhci_host *host); >> +void xenon_soc_pad_ctrl(struct sdhci_host *host, >> + unsigned char signal_voltage); >> #endif >> > > From mboxrd@z Thu Jan 1 00:00:00 1970 From: Ziji Hu Subject: Re: [PATCH 7/10] mmc: sdhci-xenon: Add support to PHYs of Marvell Xenon SDHC Date: Sat, 8 Oct 2016 17:28:47 +0800 Message-ID: References: <25146173-d98b-f346-b333-4d7466960496@rock-chips.com> Mime-Version: 1.0 Content-Type: text/plain; charset="gbk" Content-Transfer-Encoding: base64 Return-path: In-Reply-To: <25146173-d98b-f346-b333-4d7466960496@rock-chips.com> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=m.gmane.org@lists.infradead.org To: Shawn Lin , Gregory CLEMENT , Ulf Hansson , Adrian Hunter , linux-mmc@vger.kernel.org Cc: Hilbert Zhang , Andrew Lunn , Romain Perier , Liuliu Zhao , Peng Zhu , Nadav Haklai , "Jack(SH) Zhu" , Victor Gu , Doug Jones , Jisheng Zhang , Yehuda Yitschak , Marcin Wojtas , Xueping Liu , Shiwu Zhang , Yu Cao , Sebastian Hesselbarth , devicetree@vger.kernel.org, Jason Cooper , Kostya Porotchkin , Rob Herring , Ryan Gao , "Wei(SOCP) Liu" , linux-arm-kernel@lists.infradead.org, Thomas Petazzoni List-Id: devicetree@vger.kernel.org SGkgU2hhd24sCgpPbiAyMDE2LzEwLzggMTA6NDQsIFNoYXduIExpbiB3cm90ZToKPiDU2iAyMDE2 LzEwLzcgMjM6MjIsIEdyZWdvcnkgQ0xFTUVOVCDQtLXAOgo+PiBGcm9tOiBaaWppIEh1IDxodXpp amlAbWFydmVsbC5jb20+Cj4+Cj4+IE1hcnZlbGwgWGVub24gZU1NQy9TRC9TRElPIEhvc3QgQ29u dHJvbGxlciBjb250YWlucyBQSFkuCj4+IFRocmVlIHR5cGVzIG9mIFBIWXMgYXJlIHN1cHBvcnRl ZC4KPj4KPj4gQWRkIHN1cHBvcnQgdG8gbXVsdGlwbGUgdHlwZXMgb2YgUEhZcyBpbml0IGFuZCBj b25maWd1cmF0aW9uLgo+PiBBZGQgcmVnaXN0ZXIgZGVmaW5pdGlvbnMgb2YgUEhZcy4KPj4KPj4g U2lnbmVkLW9mZi1ieTogSHUgWmlqaSA8aHV6aWppQG1hcnZlbGwuY29tPgo+PiBSZXZpZXdlZC1i eTogR3JlZ29yeSBDTEVNRU5UIDxncmVnb3J5LmNsZW1lbnRAZnJlZS1lbGVjdHJvbnMuY29tPgo+ PiBTaWduZWQtb2ZmLWJ5OiBHcmVnb3J5IENMRU1FTlQgPGdyZWdvcnkuY2xlbWVudEBmcmVlLWVs ZWN0cm9ucy5jb20+Cj4+IC0tLQo+PiAgTUFJTlRBSU5FUlMgICAgICAgICAgICAgICAgICAgICAg ICB8ICAgIDEgKy0KPj4gIGRyaXZlcnMvbW1jL2hvc3QvTWFrZWZpbGUgICAgICAgICAgfCAgICAy ICstCj4+ICBkcml2ZXJzL21tYy9ob3N0L3NkaGNpLXhlbm9uLXBoeS5jIHwgMTE0MSArKysrKysr KysrKysrKysrKysrKysrKysrKysrKy0KPj4gIGRyaXZlcnMvbW1jL2hvc3Qvc2RoY2kteGVub24t cGh5LmggfCAgMTU3ICsrKystCj4+ICBkcml2ZXJzL21tYy9ob3N0L3NkaGNpLXhlbm9uLmMgICAg IHwgICAgNCArLQo+PiAgZHJpdmVycy9tbWMvaG9zdC9zZGhjaS14ZW5vbi5oICAgICB8ICAgMTcg Ky0KPj4gIDYgZmlsZXMgY2hhbmdlZCwgMTMyMSBpbnNlcnRpb25zKCspLCAxIGRlbGV0aW9uKC0p Cj4+ICBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy9tbWMvaG9zdC9zZGhjaS14ZW5vbi1waHku Ywo+PiAgY3JlYXRlIG1vZGUgMTAwNjQ0IGRyaXZlcnMvbW1jL2hvc3Qvc2RoY2kteGVub24tcGh5 LmgKPj4KPj4gZGlmZiAtLWdpdCBhL01BSU5UQUlORVJTIGIvTUFJTlRBSU5FUlMKPj4gaW5kZXgg ODU5NDIwZTVkZmQzLi5iNTY3M2MyZWU1ZjIgMTAwNjQ0Cj4+IC0tLSBhL01BSU5UQUlORVJTCj4+ ICsrKyBiL01BSU5UQUlORVJTCj4+IEBAIC03NTgzLDYgKzc1ODMsNyBAQCBNOiAgICBaaWppIEh1 IDxodXppamlAbWFydmVsbC5jb20+Cj4+ICBMOiAgICBsaW51eC1tbWNAdmdlci5rZXJuZWwub3Jn Cj4+ICBTOiAgICBTdXBwb3J0ZWQKPj4gIEY6ICAgIGRyaXZlcnMvbW1jL2hvc3Qvc2RoY2kteGVu b24uKgo+PiArRjogICAgZHJpdmVycy9tbWMvaG9zdC9zZGhjaS14ZW5vbi1waHkuKgo+IAo+IGRy aXZlcnMvbW1jL2hvc3Qvc2RoY2kteGVub24qIHNob3ViZSBlbm91Z2gKPiAKPj4gIEY6ICAgIERv Y3VtZW50YXRpb24vZGV2aWNldHJlZS9iaW5kaW5ncy9tbWMvbWFydmVsbCxzZGhjaS14ZW5vbi50 eHQKPj4KPj4gIE1BVFJPWCBGUkFNRUJVRkZFUiBEUklWRVIKPj4gZGlmZiAtLWdpdCBhL2RyaXZl cnMvbW1jL2hvc3QvTWFrZWZpbGUgYi9kcml2ZXJzL21tYy9ob3N0L01ha2VmaWxlCj4+IGluZGV4 IDc1ZWFmNzQzNDg2Yy4uNGYyODU0NTU2ZmY3IDEwMDY0NAo+PiAtLS0gYS9kcml2ZXJzL21tYy9o b3N0L01ha2VmaWxlCj4+ICsrKyBiL2RyaXZlcnMvbW1jL2hvc3QvTWFrZWZpbGUKPj4gQEAgLTgy LDQgKzgyLDQgQEAgaWZlcSAoJChDT05GSUdfQ0I3MTBfREVCVUcpLHkpCj4+ICBlbmRpZgo+Pgo+ PiAgb2JqLSQoQ09ORklHX01NQ19TREhDSV9YRU5PTikgICAgKz0gc2RoY2kteGVub24tZHJpdmVy Lm8KPj4gLXNkaGNpLXhlbm9uLWRyaXZlci15ICAgICAgICArPSBzZGhjaS14ZW5vbi5vCj4+ICtz ZGhjaS14ZW5vbi1kcml2ZXIteSAgICAgICAgKz0gc2RoY2kteGVub24ubyBzZGhjaS14ZW5vbi1w aHkubwo+PiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9tbWMvaG9zdC9zZGhjaS14ZW5vbi1waHkuYyBi L2RyaXZlcnMvbW1jL2hvc3Qvc2RoY2kteGVub24tcGh5LmMKPj4gbmV3IGZpbGUgbW9kZSAxMDA2 NDQKPj4gaW5kZXggMDAwMDAwMDAwMDAwLi40ZWI4ZmVhMWJlYzkKPj4gLS0tIC9kZXYvbnVsbAo+ PiArKysgYi9kcml2ZXJzL21tYy9ob3N0L3NkaGNpLXhlbm9uLXBoeS5jCj4gCj4gV2VsbCwgaXQn cyBsZWdpdCB0byB1c2UgcGh5IEFQSSBhbmQgbW92ZSB5b3VyIHBoeQo+IG9wZXJhdGlvbnMgdG8g UEhZIHN1YnN5c3RlbS4gOikKPiAKCiAgICBBY3R1YWxseSB3ZSB0cmllZCB0byBwdXQgdGhlIFBI WSBjb2RlIGludG8gTGludXggUEhZIGZyYW1ld29yay4KICAgIEJ1dCBpdCBjYW5ub3QgZml0IGlu IExpbnV4IGNvbW1vbiBQSFkgZnJhbWV3b3JrLgoKICAgIE91ciBYZW5vbiBTREhDIFBIWSByZWdp c3RlciBpcyBhIHBhcnQgb2YgWGVub24gU0RIQyByZWdpc3RlciBzZXQuCiAgICBCZXNpZGVzLCBk dXJpbmcgTU1DIGluaXRpYWxpemF0aW9uLCBNTUMgc2VxdWVuY2UgaGFzIHRvIGNhbGwgc2V2ZXJh bCBQSFkgZnVuY3Rpb25zIHRvIGNvbXBsZXRlIHRpbWluZyBzZXR0aW5nLgogICAgSW4gdGhvc2Ug UEhZIHNldHRpbmcgZnVuY3Rpb25zLCB0aGV5IGhhdmUgdG8gYWNjZXNzIFNESEMgcmVnaXN0ZXIg YW5kIGtub3cgY3VycmVudCBNTUMgc2V0dGluZywgc3VjaCBhcyBidXMgd2lkdGgsIGNsb2NrIGZy ZXF1ZW5jeSBhbmQgc3BlZWQgbW9kZS4KICAgIEFzIGEgcmVzdWx0LCB3ZSBoYXZlIHRvIGltcGxl bWVudCBQSFkgdW5kZXIgTU1DIGRpcmVjdG9yeS4KCiAgICBUaGFuayB5b3UuCgpCZXN0IHJlZ2Fy ZHMsCkh1IFppamkgICAgCgo+PiBAQCAtMCwwICsxLDExNDEgQEAKPj4gKy8qCj4+ICsgKiBQSFkg c3VwcG9ydCBmb3IgWGVub24gU0RIQwo+PiArICoKPj4gKyAqIENvcHlyaWdodCAoQykgMjAxNiBN YXJ2ZWxsLCBBbGwgUmlnaHRzIFJlc2VydmVkLgo+PiArICoKPj4gKyAqIEF1dGhvcjogICAgSHUg WmlqaSA8aHV6aWppQG1hcnZlbGwuY29tPgo+PiArICogRGF0ZTogICAgMjAxNi04LTI0Cj4+ICsg Kgo+PiArICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmli dXRlIGl0IGFuZC9vcgo+PiArICogbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05V IEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMKPj4gKyAqIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBT b2Z0d2FyZSBGb3VuZGF0aW9uIHZlcnNpb24gMi4KPj4gKyAqLwo+PiArCj4+ICsjaW5jbHVkZSA8 bGludXgvc2xhYi5oPgo+PiArI2luY2x1ZGUgPGxpbnV4L2RlbGF5Lmg+Cj4+ICsjaW5jbHVkZSA8 bGludXgvb2ZfYWRkcmVzcy5oPgo+PiArI2luY2x1ZGUgPGxpbnV4L21tYy9ob3N0Lmg+Cj4+ICsj aW5jbHVkZSA8bGludXgvbW1jL21tYy5oPgo+PiArI2luY2x1ZGUgPGxpbnV4L21tYy9jYXJkLmg+ Cj4+ICsjaW5jbHVkZSA8bGludXgvbW1jL3NkaW8uaD4KPj4gKwo+PiArI2luY2x1ZGUgInNkaGNp LmgiCj4+ICsjaW5jbHVkZSAic2RoY2ktcGx0Zm0uaCIKPj4gKyNpbmNsdWRlICJzZGhjaS14ZW5v bi5oIgo+PiArCj4+ICtzdGF0aWMgY29uc3QgY2hhciAqIGNvbnN0IHBoeV90eXBlc1tdID0gewo+ PiArICAgICJzZGggcGh5IiwKPj4gKyAgICAiZW1tYyA1LjAgcGh5IiwKPj4gKyAgICAiZW1tYyA1 LjEgcGh5Igo+PiArfTsKPj4gKwo+PiArZW51bSBwaHlfdHlwZV9lbnVtIHsKPj4gKyAgICBTREhf UEhZLAo+PiArICAgIEVNTUNfNV8wX1BIWSwKPj4gKyAgICBFTU1DXzVfMV9QSFksCj4+ICsgICAg TlJfUEhZX1RZUEVTCj4+ICt9Owo+PiArCj4+ICtzdHJ1Y3Qgc29jX3BhZF9jdHJsX3RhYmxlIHsK Pj4gKyAgICBjb25zdCBjaGFyICpzb2M7Cj4+ICsgICAgdm9pZCAoKnNldF9zb2NfcGFkKShzdHJ1 Y3Qgc2RoY2lfaG9zdCAqaG9zdCwKPj4gKyAgICAgICAgICAgICAgICB1bnNpZ25lZCBjaGFyIHNp Z25hbF92b2x0YWdlKTsKPj4gK307Cj4+ICsKPj4gK3N0cnVjdCBzb2NfcGFkX2N0cmwgewo+PiAr ICAgIC8qIFJlZ2lzdGVyIGFkZHJlc3Mgb2YgU09DIFBIWSBQQUQgY3RybCAqLwo+PiArICAgIHZv aWQgX19pb21lbSAgICAqcmVnOwo+PiArICAgIC8qIFNPQyBQSFkgUEFEIGN0cmwgdHlwZSAqLwo+ PiArICAgIGVudW0gc29jX3BhZF9jdHJsX3R5cGUgcGFkX3R5cGU7Cj4+ICsgICAgLyogU09DIHNw ZWNpZmljIG9wZXJhdGlvbiB0byBzZXQgU09DIFBIWSBQQUQgKi8KPj4gKyAgICB2b2lkICgqc2V0 X3NvY19wYWQpKHN0cnVjdCBzZGhjaV9ob3N0ICpob3N0LAo+PiArICAgICAgICAgICAgICAgIHVu c2lnbmVkIGNoYXIgc2lnbmFsX3ZvbHRhZ2UpOwo+PiArfTsKPj4gKwo+PiArc3RhdGljIHN0cnVj dCB4ZW5vbl9lbW1jX3BoeV9yZWdzICB4ZW5vbl9lbW1jXzVfMF9waHlfcmVncyA9IHsKPj4gKyAg ICAudGltaW5nX2FkaiAgICA9IEVNTUNfNV8wX1BIWV9USU1JTkdfQURKVVNULAo+PiArICAgIC5m dW5jX2N0cmwgICAgPSBFTU1DXzVfMF9QSFlfRlVOQ19DT05UUk9MLAo+PiArICAgIC5wYWRfY3Ry bCAgICA9IEVNTUNfNV8wX1BIWV9QQURfQ09OVFJPTCwKPj4gKyAgICAucGFkX2N0cmwyICAgID0g RU1NQ181XzBfUEhZX1BBRF9DT05UUk9MMiwKPj4gKyAgICAuZGxsX2N0cmwgICAgPSBFTU1DXzVf MF9QSFlfRExMX0NPTlRST0wsCj4+ICsgICAgLmxvZ2ljX3RpbWluZ19hZGogPSBFTU1DXzVfMF9Q SFlfTE9HSUNfVElNSU5HX0FESlVTVCwKPj4gKyAgICAuZGVsYXlfbWFzayAgICA9IEVNTUNfNV8w X1BIWV9GSVhFRF9ERUxBWV9NQVNLLAo+PiArICAgIC5kbGxfdXBkYXRlICAgID0gRExMX1VQREFU RV9TVFJPQkVfNV8wLAo+PiArfTsKPj4gKwo+PiArc3RhdGljIHN0cnVjdCB4ZW5vbl9lbW1jX3Bo eV9yZWdzICB4ZW5vbl9lbW1jXzVfMV9waHlfcmVncyA9IHsKPj4gKyAgICAudGltaW5nX2FkaiAg ICA9IEVNTUNfUEhZX1RJTUlOR19BREpVU1QsCj4+ICsgICAgLmZ1bmNfY3RybCAgICA9IEVNTUNf UEhZX0ZVTkNfQ09OVFJPTCwKPj4gKyAgICAucGFkX2N0cmwgICAgPSBFTU1DX1BIWV9QQURfQ09O VFJPTCwKPj4gKyAgICAucGFkX2N0cmwyICAgID0gRU1NQ19QSFlfUEFEX0NPTlRST0wyLAo+PiAr ICAgIC5kbGxfY3RybCAgICA9IEVNTUNfUEhZX0RMTF9DT05UUk9MLAo+PiArICAgIC5sb2dpY190 aW1pbmdfYWRqID0gRU1NQ19QSFlfTE9HSUNfVElNSU5HX0FESlVTVCwKPj4gKyAgICAuZGVsYXlf bWFzayAgICA9IEVNTUNfUEhZX0ZJWEVEX0RFTEFZX01BU0ssCj4+ICsgICAgLmRsbF91cGRhdGUg ICAgPSBETExfVVBEQVRFLAo+PiArfTsKPj4gKwo+PiArc3RhdGljIGludCB4ZW5vbl9kZWxheV9h ZGpfdGVzdChzdHJ1Y3QgbW1jX2NhcmQgKmNhcmQpOwo+PiArCj4+ICsvKgo+PiArICogZU1NQyBQ SFkgY29uZmlndXJhdGlvbiBhbmQgb3BlcmF0aW9ucwo+PiArICovCj4+ICtzdHJ1Y3QgZW1tY19w aHlfcGFyYW1zIHsKPj4gKyAgICBib29sICAgIHNsb3dfbW9kZTsKPj4gKwo+PiArICAgIHU4ICAg IHpucjsKPj4gKyAgICB1OCAgICB6cHI7Cj4+ICsKPj4gKyAgICAvKiBOciBvZiBjb25zZWN1dGl2 ZSBTYW1wbGluZyBQb2ludHMgb2YgYSBWYWxpZCBTYW1wbGluZyBXaW5kb3cgKi8KPj4gKyAgICB1 OCAgICBucl90dW5fdGltZXM7Cj4+ICsgICAgLyogRGl2aWRlciBmb3IgY2FsY3VsYXRpbmcgVHVu aW5nIFN0ZXAgKi8KPj4gKyAgICB1OCAgICB0dW5fc3RlcF9kaXZpZGVyOwo+PiArCj4+ICsgICAg c3RydWN0IHNvY19wYWRfY3RybCBwYWRfY3RybDsKPj4gK307Cj4+ICsKPj4gK3N0YXRpYyB2b2lk IHhlbm9uX2VtbWNfcGh5X3N0cm9iZV9kZWxheV9hZGooc3RydWN0IHNkaGNpX2hvc3QgKmhvc3Qs Cj4+ICsgICAgICAgICAgICAgICAgICAgICAgICBzdHJ1Y3QgbW1jX2NhcmQgKmNhcmQpOwo+PiAr c3RhdGljIGludCB4ZW5vbl9lbW1jX3BoeV9maXhfc2FtcGxfZGVsYXlfYWRqKHN0cnVjdCBzZGhj aV9ob3N0ICpob3N0LAo+PiArICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJ1Y3QgbW1jX2Nh cmQgKmNhcmQpOwo+PiArc3RhdGljIHZvaWQgeGVub25fZW1tY19waHlfc2V0KHN0cnVjdCBzZGhj aV9ob3N0ICpob3N0LAo+PiArICAgICAgICAgICAgICAgICAgIHVuc2lnbmVkIGNoYXIgdGltaW5n KTsKPj4gK3N0YXRpYyB2b2lkIHhlbm9uX2VtbWNfc2V0X3NvY19wYWQoc3RydWN0IHNkaGNpX2hv c3QgKmhvc3QsCj4+ICsgICAgICAgICAgICAgICAgICAgdW5zaWduZWQgY2hhciBzaWduYWxfdm9s dGFnZSk7Cj4+ICsKPj4gK3N0YXRpYyBjb25zdCBzdHJ1Y3QgeGVub25fcGh5X29wcyBlbW1jX3Bo eV9vcHMgPSB7Cj4+ICsgICAgLnN0cm9iZV9kZWxheV9hZGogPSB4ZW5vbl9lbW1jX3BoeV9zdHJv YmVfZGVsYXlfYWRqLAo+PiArICAgIC5maXhfc2FtcGxfZGVsYXlfYWRqID0geGVub25fZW1tY19w aHlfZml4X3NhbXBsX2RlbGF5X2FkaiwKPj4gKyAgICAucGh5X3NldCA9IHhlbm9uX2VtbWNfcGh5 X3NldCwKPj4gKyAgICAuc2V0X3NvY19wYWQgPSB4ZW5vbl9lbW1jX3NldF9zb2NfcGFkLAo+PiAr fTsKPj4gKwo+PiArc3RhdGljIGludCBhbGxvY19lbW1jX3BoeShzdHJ1Y3Qgc2RoY2lfeGVub25f cHJpdiAqcHJpdikKPj4gK3sKPj4gKyAgICBzdHJ1Y3QgZW1tY19waHlfcGFyYW1zICpwYXJhbXM7 Cj4+ICsKPj4gKyAgICBwYXJhbXMgPSBremFsbG9jKHNpemVvZigqcGFyYW1zKSwgR0ZQX0tFUk5F TCk7Cj4+ICsgICAgaWYgKCFwYXJhbXMpCj4+ICsgICAgICAgIHJldHVybiAtRU5PTUVNOwo+PiAr Cj4+ICsgICAgcHJpdi0+cGh5X3BhcmFtcyA9IHBhcmFtczsKPj4gKyAgICBwcml2LT5waHlfb3Bz ID0gJmVtbWNfcGh5X29wczsKPj4gKyAgICBpZiAocHJpdi0+cGh5X3R5cGUgPT0gRU1NQ181XzBf UEhZKQo+PiArICAgICAgICBwcml2LT5lbW1jX3BoeV9yZWdzID0gJnhlbm9uX2VtbWNfNV8wX3Bo eV9yZWdzOwo+PiArICAgIGVsc2UKPj4gKyAgICAgICAgcHJpdi0+ZW1tY19waHlfcmVncyA9ICZ4 ZW5vbl9lbW1jXzVfMV9waHlfcmVnczsKPj4gKwo+PiArICAgIHJldHVybiAwOwo+PiArfQo+PiAr Cj4+ICtzdGF0aWMgaW50IHhlbm9uX2VtbWNfcGh5X2luaXQoc3RydWN0IHNkaGNpX2hvc3QgKmhv c3QpCj4+ICt7Cj4+ICsgICAgdTMyIHJlZzsKPj4gKyAgICB1MzIgd2FpdCwgY2xvY2s7Cj4+ICsg ICAgc3RydWN0IHNkaGNpX3BsdGZtX2hvc3QgKnBsdGZtX2hvc3QgPSBzZGhjaV9wcml2KGhvc3Qp Owo+PiArICAgIHN0cnVjdCBzZGhjaV94ZW5vbl9wcml2ICpwcml2ID0gc2RoY2lfcGx0Zm1fcHJp dihwbHRmbV9ob3N0KTsKPj4gKyAgICBzdHJ1Y3QgeGVub25fZW1tY19waHlfcmVncyAqcGh5X3Jl Z3MgPSBwcml2LT5lbW1jX3BoeV9yZWdzOwo+PiArCj4+ICsgICAgcmVnID0gc2RoY2lfcmVhZGwo aG9zdCwgcGh5X3JlZ3MtPnRpbWluZ19hZGopOwo+PiArICAgIHJlZyB8PSBQSFlfSU5JVElBTEla QUlPTjsKPj4gKyAgICBzZGhjaV93cml0ZWwoaG9zdCwgcmVnLCBwaHlfcmVncy0+dGltaW5nX2Fk aik7Cj4+ICsKPj4gKyAgICAvKiBBZGQgZHVyYXRpb24gb2YgRkNfU1lOQ19SU1QgKi8KPj4gKyAg ICB3YWl0ID0gKChyZWcgPj4gRkNfU1lOQ19SU1RfRFVSQVRJT05fU0hJRlQpICYKPj4gKyAgICAg ICAgICAgIEZDX1NZTkNfUlNUX0RVUkFUSU9OX01BU0spOwo+PiArICAgIC8qIEFkZCBpbnRlcnZh bCBiZXR3ZWVuIEZDX1NZTkNfRU4gYW5kIEZDX1NZTkNfUlNUICovCj4+ICsgICAgd2FpdCArPSAo KHJlZyA+PiBGQ19TWU5DX1JTVF9FTl9EVVJBVElPTl9TSElGVCkgJgo+PiArICAgICAgICAgICAg RkNfU1lOQ19SU1RfRU5fRFVSQVRJT05fTUFTSyk7Cj4+ICsgICAgLyogQWRkIGR1cmF0aW9uIG9m IGFzc2VydGluZyBGQ19TWU5DX0VOICovCj4+ICsgICAgd2FpdCArPSAoKHJlZyA+PiBGQ19TWU5D X0VOX0RVUkFUSU9OX1NISUZUKSAmCj4+ICsgICAgICAgICAgICBGQ19TWU5DX0VOX0RVUkFUSU9O X01BU0spOwo+PiArICAgIC8qIEFkZCBkdXJhdGlvbiBvZiB3YWl0aW5nIGZvciBQSFkgKi8KPj4g KyAgICB3YWl0ICs9ICgocmVnID4+IFdBSVRfQ1lDTEVfQkVGT1JFX1VTSU5HX1NISUZUKSAmCj4+ ICsgICAgICAgICAgICBXQUlUX0NZQ0xFX0JFRk9SRV9VU0lOR19NQVNLKTsKPj4gKyAgICAvKiA0 IGFkZHRpb25hbCBidXMgY2xvY2sgYW5kIDQgQVhJIGJ1cyBjbG9jayBhcmUgcmVxdWlyZWQgKi8K Pj4gKyAgICB3YWl0ICs9IDg7Cj4+ICsgICAgd2FpdCA8PD0gMjA7Cj4+ICsKPj4gKyAgICBjbG9j ayA9IGhvc3QtPmNsb2NrOwo+PiArICAgIGlmICghY2xvY2spCj4+ICsgICAgICAgIC8qIFVzZSB0 aGUgcG9zc2libHkgc2xvd2VzdCBidXMgZnJlcXVlbmN5IHZhbHVlICovCj4+ICsgICAgICAgIGNs b2NrID0gTE9XRVNUX1NEQ0xLX0ZSRVE7Cj4+ICsgICAgLyogZ2V0IHRoZSB3YWl0IHRpbWUgKi8K Pj4gKyAgICB3YWl0IC89IGNsb2NrOwo+PiArICAgIHdhaXQrKzsKPj4gKyAgICAvKiB3YWl0IGZv ciBob3N0IGVNTUMgUEhZIGluaXQgY29tcGxldGVzICovCj4+ICsgICAgdWRlbGF5KHdhaXQpOwo+ PiArCj4+ICsgICAgcmVnID0gc2RoY2lfcmVhZGwoaG9zdCwgcGh5X3JlZ3MtPnRpbWluZ19hZGop Owo+PiArICAgIHJlZyAmPSBQSFlfSU5JVElBTElaQUlPTjsKPj4gKyAgICBpZiAocmVnKSB7Cj4+ ICsgICAgICAgIGRldl9lcnIobW1jX2Rldihob3N0LT5tbWMpLCAiZU1NQyBQSFkgaW5pdCBjYW5u b3QgY29tcGxldGUgYWZ0ZXIgJWQgdXNcbiIsCj4+ICsgICAgICAgICAgICB3YWl0KTsKPj4gKyAg ICAgICAgcmV0dXJuIC1FVElNRURPVVQ7Cj4+ICsgICAgfQo+PiArCj4+ICsgICAgcmV0dXJuIDA7 Cj4+ICt9Cj4+ICsKPj4gKyNkZWZpbmUgQVJNQURBXzM3MDBfU09DX1BBRF8xXzhWICAgIDB4MQo+ PiArI2RlZmluZSBBUk1BREFfMzcwMF9TT0NfUEFEXzNfM1YgICAgMHgwCj4+ICsKPj4gK3N0YXRp YyB2b2lkIGFybWFkYV8zNzAwX3NvY19wYWRfdm9sdGFnZV9zZXQoc3RydWN0IHNkaGNpX2hvc3Qg Kmhvc3QsCj4+ICsgICAgICAgICAgICAgICAgICAgICAgICB1bnNpZ25lZCBjaGFyIHNpZ25hbF92 b2x0YWdlKQo+PiArewo+PiArICAgIHN0cnVjdCBzZGhjaV9wbHRmbV9ob3N0ICpwbHRmbV9ob3N0 ID0gc2RoY2lfcHJpdihob3N0KTsKPj4gKyAgICBzdHJ1Y3Qgc2RoY2lfeGVub25fcHJpdiAqcHJp diA9IHNkaGNpX3BsdGZtX3ByaXYocGx0Zm1faG9zdCk7Cj4+ICsgICAgc3RydWN0IGVtbWNfcGh5 X3BhcmFtcyAqcGFyYW1zID0gcHJpdi0+cGh5X3BhcmFtczsKPj4gKwo+PiArICAgIGlmIChwYXJh bXMtPnBhZF9jdHJsLnBhZF90eXBlID09IFNPQ19QQURfRklYRURfMV84Vikgewo+PiArICAgICAg ICB3cml0ZWwoQVJNQURBXzM3MDBfU09DX1BBRF8xXzhWLCBwYXJhbXMtPnBhZF9jdHJsLnJlZyk7 Cj4+ICsgICAgfSBlbHNlIGlmIChwYXJhbXMtPnBhZF9jdHJsLnBhZF90eXBlID09IFNPQ19QQURf U0QpIHsKPj4gKyAgICAgICAgaWYgKHNpZ25hbF92b2x0YWdlID09IE1NQ19TSUdOQUxfVk9MVEFH RV8xODApCj4+ICsgICAgICAgICAgICB3cml0ZWwoQVJNQURBXzM3MDBfU09DX1BBRF8xXzhWLCBw YXJhbXMtPnBhZF9jdHJsLnJlZyk7Cj4+ICsgICAgICAgIGVsc2UgaWYgKHNpZ25hbF92b2x0YWdl ID09IE1NQ19TSUdOQUxfVk9MVEFHRV8zMzApCj4+ICsgICAgICAgICAgICB3cml0ZWwoQVJNQURB XzM3MDBfU09DX1BBRF8zXzNWLCBwYXJhbXMtPnBhZF9jdHJsLnJlZyk7Cj4+ICsgICAgfQo+PiAr fQo+PiArCj4+ICtzdGF0aWMgdm9pZCB4ZW5vbl9lbW1jX3NldF9zb2NfcGFkKHN0cnVjdCBzZGhj aV9ob3N0ICpob3N0LAo+PiArICAgICAgICAgICAgICAgICAgIHVuc2lnbmVkIGNoYXIgc2lnbmFs X3ZvbHRhZ2UpCj4+ICt7Cj4+ICsgICAgc3RydWN0IHNkaGNpX3BsdGZtX2hvc3QgKnBsdGZtX2hv c3QgPSBzZGhjaV9wcml2KGhvc3QpOwo+PiArICAgIHN0cnVjdCBzZGhjaV94ZW5vbl9wcml2ICpw cml2ID0gc2RoY2lfcGx0Zm1fcHJpdihwbHRmbV9ob3N0KTsKPj4gKyAgICBzdHJ1Y3QgZW1tY19w aHlfcGFyYW1zICpwYXJhbXMgPSBwcml2LT5waHlfcGFyYW1zOwo+PiArCj4+ICsgICAgaWYgKCFw YXJhbXMtPnBhZF9jdHJsLnJlZykKPj4gKyAgICAgICAgcmV0dXJuOwo+PiArCj4+ICsgICAgaWYg KHBhcmFtcy0+cGFkX2N0cmwuc2V0X3NvY19wYWQpCj4+ICsgICAgICAgIHBhcmFtcy0+cGFkX2N0 cmwuc2V0X3NvY19wYWQoaG9zdCwgc2lnbmFsX3ZvbHRhZ2UpOwo+PiArfQo+PiArCj4+ICtzdGF0 aWMgaW50IGVtbWNfcGh5X3NldF9maXhfc2FtcGxfZGVsYXkoc3RydWN0IHNkaGNpX2hvc3QgKmhv c3QsCj4+ICsgICAgICAgICAgICAgICAgICAgIHVuc2lnbmVkIGludCBkZWxheSwKPj4gKyAgICAg ICAgICAgICAgICAgICAgYm9vbCBpbnZlcnQsCj4+ICsgICAgICAgICAgICAgICAgICAgIGJvb2wg ZGVsYXlfOTBfZGVncmVlKQo+PiArewo+PiArICAgIHUzMiByZWc7Cj4+ICsgICAgdW5zaWduZWQg bG9uZyBmbGFnczsKPj4gKyAgICBzdHJ1Y3Qgc2RoY2lfcGx0Zm1faG9zdCAqcGx0Zm1faG9zdCA9 IHNkaGNpX3ByaXYoaG9zdCk7Cj4+ICsgICAgc3RydWN0IHNkaGNpX3hlbm9uX3ByaXYgKnByaXYg PSBzZGhjaV9wbHRmbV9wcml2KHBsdGZtX2hvc3QpOwo+PiArICAgIHN0cnVjdCB4ZW5vbl9lbW1j X3BoeV9yZWdzICpwaHlfcmVncyA9IHByaXYtPmVtbWNfcGh5X3JlZ3M7Cj4+ICsgICAgaW50IHJl dCA9IDA7Cj4+ICsKPj4gKyAgICBzcGluX2xvY2tfaXJxc2F2ZSgmaG9zdC0+bG9jaywgZmxhZ3Mp Owo+PiArCj4+ICsgICAgLyogU2V0dXAgU2FtcGxpbmcgZml4IGRlbGF5ICovCj4+ICsgICAgcmVn ID0gc2RoY2lfcmVhZGwoaG9zdCwgU0RIQ19TTE9UX09QX1NUQVRVU19DVFJMKTsKPj4gKyAgICBy ZWcgJj0gfnBoeV9yZWdzLT5kZWxheV9tYXNrOwo+PiArICAgIHJlZyB8PSBkZWxheSAmIHBoeV9y ZWdzLT5kZWxheV9tYXNrOwo+PiArICAgIHNkaGNpX3dyaXRlbChob3N0LCByZWcsIFNESENfU0xP VF9PUF9TVEFUVVNfQ1RSTCk7Cj4+ICsKPj4gKyAgICBpZiAocHJpdi0+cGh5X3R5cGUgPT0gRU1N Q181XzBfUEhZKSB7Cj4+ICsgICAgICAgIC8qIHNldCA5MCBkZWdyZWUgcGhhc2UgaWYgbmVjZXNz YXJ5ICovCj4+ICsgICAgICAgIHJlZyAmPSB+REVMQVlfOTBfREVHUkVFX01BU0tfRU1NQzU7Cj4+ ICsgICAgICAgIHJlZyB8PSAoZGVsYXlfOTBfZGVncmVlIDw8IERFTEFZXzkwX0RFR1JFRV9TSElG VF9FTU1DNSk7Cj4+ICsgICAgICAgIHNkaGNpX3dyaXRlbChob3N0LCByZWcsIFNESENfU0xPVF9P UF9TVEFUVVNfQ1RSTCk7Cj4+ICsgICAgfQo+PiArCj4+ICsgICAgLyogRGlzYWJsZSBTRENMSyAq Lwo+PiArICAgIHJlZyA9IHNkaGNpX3JlYWRsKGhvc3QsIFNESENJX0NMT0NLX0NPTlRST0wpOwo+ PiArICAgIHJlZyAmPSB+KFNESENJX0NMT0NLX0NBUkRfRU4gfCBTREhDSV9DTE9DS19JTlRfRU4p Owo+PiArICAgIHNkaGNpX3dyaXRlbChob3N0LCByZWcsIFNESENJX0NMT0NLX0NPTlRST0wpOwo+ PiArCj4+ICsgICAgdWRlbGF5KDIwMCk7Cj4+ICsKPj4gKyAgICBpZiAocHJpdi0+cGh5X3R5cGUg PT0gRU1NQ181XzFfUEhZKSB7Cj4+ICsgICAgICAgIC8qIHNldCA5MCBkZWdyZWUgcGhhc2UgaWYg bmVjZXNzYXJ5ICovCj4+ICsgICAgICAgIHJlZyA9IHNkaGNpX3JlYWRsKGhvc3QsIEVNTUNfUEhZ X0ZVTkNfQ09OVFJPTCk7Cj4+ICsgICAgICAgIHJlZyAmPSB+QVNZTkNfRERSTU9ERV9NQVNLOwo+ PiArICAgICAgICByZWcgfD0gKGRlbGF5XzkwX2RlZ3JlZSA8PCBBU1lOQ19ERFJNT0RFX1NISUZU KTsKPj4gKyAgICAgICAgc2RoY2lfd3JpdGVsKGhvc3QsIHJlZywgRU1NQ19QSFlfRlVOQ19DT05U Uk9MKTsKPj4gKyAgICB9Cj4+ICsKPj4gKyAgICAvKiBTZXR1cCBJbnZlcnNpb24gb2YgU2FtcGxp bmcgZWRnZSAqLwo+PiArICAgIHJlZyA9IHNkaGNpX3JlYWRsKGhvc3QsIHBoeV9yZWdzLT50aW1p bmdfYWRqKTsKPj4gKyAgICByZWcgJj0gflNBTVBMX0lOVl9RU1BfUEhBU0VfU0VMRUNUOwo+PiAr ICAgIHJlZyB8PSAoaW52ZXJ0IDw8IFNBTVBMX0lOVl9RU1BfUEhBU0VfU0VMRUNUX1NISUZUKTsK Pj4gKyAgICBzZGhjaV93cml0ZWwoaG9zdCwgcmVnLCBwaHlfcmVncy0+dGltaW5nX2Fkaik7Cj4+ ICsKPj4gKyAgICAvKiBFbmFibGUgU0QgaW50ZXJuYWwgY2xvY2sgKi8KPj4gKyAgICByZXQgPSBl bmFibGVfeGVub25faW50ZXJuYWxfY2xrKGhvc3QpOwo+PiArICAgIGlmIChyZXQpCj4+ICsgICAg ICAgIGdvdG8gb3V0Owo+PiArCj4+ICsgICAgLyogRW5hYmxlIFNEQ0xLICovCj4+ICsgICAgcmVn ID0gc2RoY2lfcmVhZGwoaG9zdCwgU0RIQ0lfQ0xPQ0tfQ09OVFJPTCk7Cj4+ICsgICAgcmVnIHw9 IFNESENJX0NMT0NLX0NBUkRfRU47Cj4+ICsgICAgc2RoY2lfd3JpdGVsKGhvc3QsIHJlZywgU0RI Q0lfQ0xPQ0tfQ09OVFJPTCk7Cj4+ICsKPj4gKyAgICB1ZGVsYXkoMjAwKTsKPj4gKwo+PiArICAg IC8qCj4+ICsgICAgICogSGFzIHRvIHJlLWluaXRpYWxpemUgZU1NQyBQSFkgaGVyZSB0byBhY3Rp dmUgUEhZCj4+ICsgICAgICogYmVjYXVzZSBsYXRlciBnZXQgc3RhdHVzIGNtZCB3aWxsIGJlIGlz c3VlZC4KPj4gKyAgICAgKi8KPj4gKyAgICByZXQgPSB4ZW5vbl9lbW1jX3BoeV9pbml0KGhvc3Qp Owo+PiArCj4+ICtvdXQ6Cj4+ICsgICAgc3Bpbl91bmxvY2tfaXJxcmVzdG9yZSgmaG9zdC0+bG9j aywgZmxhZ3MpOwo+PiArICAgIHJldHVybiByZXQ7Cj4+ICt9Cj4+ICsKPj4gK3N0YXRpYyBpbnQg ZW1tY19waHlfZG9fZml4X3NhbXBsX2RlbGF5KHN0cnVjdCBzZGhjaV9ob3N0ICpob3N0LAo+PiAr ICAgICAgICAgICAgICAgICAgICAgICBzdHJ1Y3QgbW1jX2NhcmQgKmNhcmQsCj4+ICsgICAgICAg ICAgICAgICAgICAgICAgIHVuc2lnbmVkIGludCBkZWxheSwKPj4gKyAgICAgICAgICAgICAgICAg ICAgICAgYm9vbCBpbnZlcnQsIGJvb2wgcXVhcnRlcikKPj4gK3sKPj4gKyAgICBpbnQgcmV0Owo+ PiArCj4+ICsgICAgZW1tY19waHlfc2V0X2ZpeF9zYW1wbF9kZWxheShob3N0LCBkZWxheSwgaW52 ZXJ0LCBxdWFydGVyKTsKPj4gKwo+PiArICAgIHJldCA9IHhlbm9uX2RlbGF5X2Fkal90ZXN0KGNh cmQpOwo+PiArICAgIGlmIChyZXQpIHsKPj4gKyAgICAgICAgZGV2X2RiZyhtbWNfZGV2KGhvc3Qt Pm1tYyksCj4+ICsgICAgICAgICAgICAiZmFpbCB3aGVuIHNhbXBsaW5nIGZpeCBkZWxheSA9ICVk LCBwaGFzZSA9ICVkIGRlZ3JlZVxuIiwKPj4gKyAgICAgICAgICAgIGRlbGF5LCBpbnZlcnQgKiAx ODAgKyBxdWFydGVyICogOTApOwo+PiArICAgICAgICByZXR1cm4gLTE7Cj4+ICsgICAgfQo+PiAr ICAgIHJldHVybiAwOwo+PiArfQo+PiArCj4+ICtzdGF0aWMgaW50IHhlbm9uX2VtbWNfcGh5X2Zp eF9zYW1wbF9kZWxheV9hZGooc3RydWN0IHNkaGNpX2hvc3QgKmhvc3QsCj4+ICsgICAgICAgICAg ICAgICAgICAgICAgICAgIHN0cnVjdCBtbWNfY2FyZCAqY2FyZCkKPj4gK3sKPj4gKyAgICBlbnVt IHNhbXBsX2ZpeF9kZWxheV9waGFzZSBwaGFzZTsKPj4gKyAgICBpbnQgaWR4LCBucl9wYWlyOwo+ PiArICAgIGludCByZXQ7Cj4+ICsgICAgdW5zaWduZWQgaW50IGRlbGF5Owo+PiArICAgIHVuc2ln bmVkIGludCBtaW5fZGVsYXksIG1heF9kZWxheTsKPj4gKyAgICBib29sIGludmVydCwgcXVhcnRl cjsKPj4gKyAgICBzdHJ1Y3Qgc2RoY2lfcGx0Zm1faG9zdCAqcGx0Zm1faG9zdCA9IHNkaGNpX3By aXYoaG9zdCk7Cj4+ICsgICAgc3RydWN0IHNkaGNpX3hlbm9uX3ByaXYgKnByaXYgPSBzZGhjaV9w bHRmbV9wcml2KHBsdGZtX2hvc3QpOwo+PiArICAgIHN0cnVjdCB4ZW5vbl9lbW1jX3BoeV9yZWdz ICpwaHlfcmVncyA9IHByaXYtPmVtbWNfcGh5X3JlZ3M7Cj4+ICsgICAgdTMyIGNvYXJzZV9zdGVw LCBmaW5lX3N0ZXA7Cj4+ICsgICAgY29uc3QgZW51bSBzYW1wbF9maXhfZGVsYXlfcGhhc2UgZGVs YXlfZWRnZVtdID0gewo+PiArICAgICAgICBQSEFTRV8wX0RFR1JFRSwKPj4gKyAgICAgICAgUEhB U0VfMTgwX0RFR1JFRSwKPj4gKyAgICAgICAgUEhBU0VfOTBfREVHUkVFLAo+PiArICAgICAgICBQ SEFTRV8yNzBfREVHUkVFCj4+ICsgICAgfTsKPj4gKwo+PiArICAgIGNvYXJzZV9zdGVwID0gcGh5 X3JlZ3MtPmRlbGF5X21hc2sgPj4gMTsKPj4gKyAgICBmaW5lX3N0ZXAgPSBjb2Fyc2Vfc3RlcCA+ PiAyOwo+PiArCj4+ICsgICAgbnJfcGFpciA9IEFSUkFZX1NJWkUoZGVsYXlfZWRnZSk7Cj4+ICsK Pj4gKyAgICBmb3IgKGlkeCA9IDA7IGlkeCA8IG5yX3BhaXI7IGlkeCsrKSB7Cj4+ICsgICAgICAg IHBoYXNlID0gZGVsYXlfZWRnZVtpZHhdOwo+PiArICAgICAgICBpbnZlcnQgPSAocGhhc2UgJiAw eDIpID8gdHJ1ZSA6IGZhbHNlOwo+PiArICAgICAgICBxdWFydGVyID0gKHBoYXNlICYgMHgxKSA/ IHRydWUgOiBmYWxzZTsKPj4gKwo+PiArICAgICAgICAvKiBpbmNyZWFzZSBkZWxheSB2YWx1ZSB0 byBnZXQgZml4IGRlbGF5ICovCj4+ICsgICAgICAgIGZvciAobWluX2RlbGF5ID0gMDsKPj4gKyAg ICAgICAgICAgICBtaW5fZGVsYXkgPD0gcGh5X3JlZ3MtPmRlbGF5X21hc2s7Cj4+ICsgICAgICAg ICAgICAgbWluX2RlbGF5ICs9IGNvYXJzZV9zdGVwKSB7Cj4+ICsgICAgICAgICAgICByZXQgPSBl bW1jX3BoeV9kb19maXhfc2FtcGxfZGVsYXkoaG9zdCwgY2FyZCwgbWluX2RlbGF5LAo+PiArICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgaW52ZXJ0LCBxdWFydGVyKTsKPj4gKyAgICAgICAg ICAgIGlmICghcmV0KQo+PiArICAgICAgICAgICAgICAgIGJyZWFrOwo+PiArICAgICAgICB9Cj4+ ICsKPj4gKyAgICAgICAgaWYgKHJldCkgewo+PiArICAgICAgICAgICAgZGV2X2RiZyhtbWNfZGV2 KGhvc3QtPm1tYyksCj4+ICsgICAgICAgICAgICAgICAgIkZhaWwgdG8gc2V0IFNhbXBsaW5nIEZp eGVkIERlbGF5IHdpdGggcGhhc2UgPSAlZCBkZWdyZWVcbiIsCj4+ICsgICAgICAgICAgICAgICAg cGhhc2UgKiA5MCk7Cj4+ICsgICAgICAgICAgICBjb250aW51ZTsKPj4gKyAgICAgICAgfQo+PiAr Cj4+ICsgICAgICAgIGZvciAobWF4X2RlbGF5ID0gbWluX2RlbGF5ICsgZmluZV9zdGVwOwo+PiAr ICAgICAgICAgICAgIG1heF9kZWxheSA8IHBoeV9yZWdzLT5kZWxheV9tYXNrOwo+PiArICAgICAg ICAgICAgIG1heF9kZWxheSArPSBmaW5lX3N0ZXApIHsKPj4gKyAgICAgICAgICAgIHJldCA9IGVt bWNfcGh5X2RvX2ZpeF9zYW1wbF9kZWxheShob3N0LCBjYXJkLCBtYXhfZGVsYXksCj4+ICsgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICBpbnZlcnQsIHF1YXJ0ZXIpOwo+PiArICAgICAgICAg ICAgaWYgKHJldCkgewo+PiArICAgICAgICAgICAgICAgIG1heF9kZWxheSAtPSBmaW5lX3N0ZXA7 Cj4+ICsgICAgICAgICAgICAgICAgYnJlYWs7Cj4+ICsgICAgICAgICAgICB9Cj4+ICsgICAgICAg IH0KPj4gKwo+PiArICAgICAgICBpZiAoIXJldCkgewo+PiArICAgICAgICAgICAgcmV0ID0gZW1t Y19waHlfZG9fZml4X3NhbXBsX2RlbGF5KGhvc3QsIGNhcmQsCj4+ICsgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICBwaHlfcmVncy0+ZGVsYXlfbWFzaywKPj4gKyAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgIGludmVydCwgcXVhcnRlcik7Cj4+ICsgICAgICAgICAgICBpZiAoIXJldCkK Pj4gKyAgICAgICAgICAgICAgICBtYXhfZGVsYXkgPSBwaHlfcmVncy0+ZGVsYXlfbWFzazsKPj4g KyAgICAgICAgfQo+PiArCj4+ICsgICAgICAgIC8qCj4+ICsgICAgICAgICAqIFNhbXBsaW5nIEZp eGVkIERlbGF5IGxpbmUgd2luZG93IHNob3VsZCBiZSBsYXJnZSBlbm91Z2gsCj4+ICsgICAgICAg ICAqIHRodXMgdGhlIHNhbXBsaW5nIHBvaW50ICh0aGUgbWlkZGxlIG9mIHRoZSB3aW5kb3cpCj4+ ICsgICAgICAgICAqIGNhbiB3b3JrIHdoZW4gZW52aXJvbm1lbnQgdmFyaWVzLgo+PiArICAgICAg ICAgKiBIb3dldmVyLCB0aGVyZSBpcyBubyBjbGVhciBjb25jbHVzaW9uIGhvdyBsYXJnZSB0aGUg d2luZG93Cj4+ICsgICAgICAgICAqIHNob3VsZCBiZS4KPj4gKyAgICAgICAgICovCj4+ICsgICAg ICAgIGlmICgobWF4X2RlbGF5IC0gbWluX2RlbGF5KSA8PQo+PiArICAgICAgICAgICAgRU1NQ19Q SFlfRklYRURfREVMQVlfV0lORE9XX01JTikgewo+PiArICAgICAgICAgICAgZGV2X2luZm8obW1j X2Rldihob3N0LT5tbWMpLAo+PiArICAgICAgICAgICAgICAgICAiVGhlIHdpbmRvdyBzaXplICVk IHdpdGggcGhhc2UgPSAlZCBkZWdyZWUgaXMgdG9vIHNtYWxsXG4iLAo+PiArICAgICAgICAgICAg ICAgICBtYXhfZGVsYXkgLSBtaW5fZGVsYXksIHBoYXNlICogOTApOwo+PiArICAgICAgICAgICAg Y29udGludWU7Cj4+ICsgICAgICAgIH0KPj4gKwo+PiArICAgICAgICBkZWxheSA9IChtaW5fZGVs YXkgKyBtYXhfZGVsYXkpIC8gMjsKPj4gKyAgICAgICAgZW1tY19waHlfc2V0X2ZpeF9zYW1wbF9k ZWxheShob3N0LCBkZWxheSwgaW52ZXJ0LCBxdWFydGVyKTsKPj4gKyAgICAgICAgZGV2X2RiZyht bWNfZGV2KGhvc3QtPm1tYyksCj4+ICsgICAgICAgICAgICAic2FtcGxpbmcgZml4IGRlbGF5ID0g JWQgd2l0aCBwaGFzZSA9ICVkIGRlZ3JlZVxuIiwKPj4gKyAgICAgICAgICAgIGRlbGF5LCBwaGFz ZSAqIDkwKTsKPj4gKyAgICAgICAgcmV0dXJuIDA7Cj4+ICsgICAgfQo+PiArCj4+ICsgICAgcmV0 dXJuIC1FSU87Cj4+ICt9Cj4+ICsKPj4gK3N0YXRpYyBpbnQgeGVub25fZW1tY19waHlfZW5hYmxl X2RsbChzdHJ1Y3Qgc2RoY2lfaG9zdCAqaG9zdCkKPj4gK3sKPj4gKyAgICB1MzIgcmVnOwo+PiAr ICAgIHN0cnVjdCBzZGhjaV9wbHRmbV9ob3N0ICpwbHRmbV9ob3N0ID0gc2RoY2lfcHJpdihob3N0 KTsKPj4gKyAgICBzdHJ1Y3Qgc2RoY2lfeGVub25fcHJpdiAqcHJpdiA9IHNkaGNpX3BsdGZtX3By aXYocGx0Zm1faG9zdCk7Cj4+ICsgICAgc3RydWN0IHhlbm9uX2VtbWNfcGh5X3JlZ3MgKnBoeV9y ZWdzID0gcHJpdi0+ZW1tY19waHlfcmVnczsKPj4gKyAgICB1OCB0aW1lb3V0Owo+PiArCj4+ICsg ICAgaWYgKFdBUk5fT04oaG9zdC0+Y2xvY2sgPD0gTU1DX0hJR0hfNTJfTUFYX0RUUikpCj4+ICsg ICAgICAgIHJldHVybiAtRUlOVkFMOwo+PiArCj4+ICsgICAgcmVnID0gc2RoY2lfcmVhZGwoaG9z dCwgcGh5X3JlZ3MtPmRsbF9jdHJsKTsKPj4gKyAgICBpZiAocmVnICYgRExMX0VOQUJMRSkKPj4g KyAgICAgICAgcmV0dXJuIDA7Cj4+ICsKPj4gKyAgICAvKiBFbmFibGUgRExMICovCj4+ICsgICAg cmVnID0gc2RoY2lfcmVhZGwoaG9zdCwgcGh5X3JlZ3MtPmRsbF9jdHJsKTsKPj4gKyAgICByZWcg fD0gKERMTF9FTkFCTEUgfCBETExfRkFTVF9MT0NLKTsKPj4gKwo+PiArICAgIC8qCj4+ICsgICAg ICogU2V0IFBoYXNlIGFzIDkwIGRlZ3JlZSwgd2hpY2ggaXMgbW9zdCBjb21tb24gdmFsdWUuCj4+ ICsgICAgICogTWlnaHQgc2V0IGFub3RoZXIgdmFsdWUgaWYgbmVjZXNzYXJ5Lgo+PiArICAgICAq IFRoZSBncmFudWxhcml0eSBpcyAxIGRlZ3JlZS4KPj4gKyAgICAgKi8KPj4gKyAgICByZWcgJj0g figoRExMX1BIQVNFX01BU0sgPDwgRExMX1BIU0VMMF9TSElGVCkgfAo+PiArICAgICAgICAgICAg KERMTF9QSEFTRV9NQVNLIDw8IERMTF9QSFNFTDFfU0hJRlQpKTsKPj4gKyAgICByZWcgfD0gKChE TExfUEhBU0VfOTBfREVHUkVFIDw8IERMTF9QSFNFTDBfU0hJRlQpIHwKPj4gKyAgICAgICAgICAg IChETExfUEhBU0VfOTBfREVHUkVFIDw8IERMTF9QSFNFTDFfU0hJRlQpKTsKPj4gKwo+PiArICAg IHJlZyAmPSB+RExMX0JZUEFTU19FTjsKPj4gKyAgICByZWcgfD0gcGh5X3JlZ3MtPmRsbF91cGRh dGU7Cj4+ICsgICAgaWYgKHByaXYtPnBoeV90eXBlID09IEVNTUNfNV8xX1BIWSkKPj4gKyAgICAg ICAgcmVnICY9IH5ETExfUkVGQ0xLX1NFTDsKPj4gKyAgICBzZGhjaV93cml0ZWwoaG9zdCwgcmVn LCBwaHlfcmVncy0+ZGxsX2N0cmwpOwo+PiArCj4+ICsgICAgLyogV2FpdCBtYXggMzIgbXMgKi8K Pj4gKyAgICB0aW1lb3V0ID0gMzI7Cj4+ICsgICAgd2hpbGUgKCEoc2RoY2lfcmVhZHcoaG9zdCwg U0RIQ19TTE9UX0VYVF9QUkVTRU5UX1NUQVRFKSAmIExPQ0tfU1RBVEUpKSB7Cj4+ICsgICAgICAg IGlmICghdGltZW91dCkgewo+PiArICAgICAgICAgICAgZGV2X2VycihtbWNfZGV2KGhvc3QtPm1t YyksICJXYWl0IGZvciBETEwgTG9jayB0aW1lLW91dFxuIik7Cj4+ICsgICAgICAgICAgICByZXR1 cm4gLUVUSU1FRE9VVDsKPj4gKyAgICAgICAgfQo+PiArICAgICAgICB0aW1lb3V0LS07Cj4+ICsg ICAgICAgIG1kZWxheSgxKTsKPj4gKyAgICB9Cj4+ICsgICAgcmV0dXJuIDA7Cj4+ICt9Cj4+ICsK Pj4gK3N0YXRpYyBpbnQgX19lbW1jX3BoeV9jb25maWdfdHVuaW5nKHN0cnVjdCBzZGhjaV9ob3N0 ICpob3N0KQo+PiArewo+PiArICAgIHN0cnVjdCBzZGhjaV9wbHRmbV9ob3N0ICpwbHRmbV9ob3N0 ID0gc2RoY2lfcHJpdihob3N0KTsKPj4gKyAgICBzdHJ1Y3Qgc2RoY2lfeGVub25fcHJpdiAqcHJp diA9IHNkaGNpX3BsdGZtX3ByaXYocGx0Zm1faG9zdCk7Cj4+ICsgICAgc3RydWN0IGVtbWNfcGh5 X3BhcmFtcyAqcGFyYW1zID0gcHJpdi0+cGh5X3BhcmFtczsKPj4gKyAgICB1MzIgcmVnLCB0dW5p bmdfc3RlcDsKPj4gKyAgICBpbnQgcmV0Owo+PiArICAgIHVuc2lnbmVkIGxvbmcgZmxhZ3M7Cj4+ ICsKPj4gKyAgICBpZiAoV0FSTl9PTihob3N0LT5jbG9jayA8PSBNTUNfSElHSF81Ml9NQVhfRFRS KSkKPj4gKyAgICAgICAgcmV0dXJuIC1FSU5WQUw7Cj4+ICsKPj4gKyAgICBzcGluX2xvY2tfaXJx c2F2ZSgmaG9zdC0+bG9jaywgZmxhZ3MpOwo+PiArCj4+ICsgICAgcmV0ID0geGVub25fZW1tY19w aHlfZW5hYmxlX2RsbChob3N0KTsKPj4gKyAgICBpZiAocmV0KSB7Cj4+ICsgICAgICAgIHNwaW5f dW5sb2NrX2lycXJlc3RvcmUoJmhvc3QtPmxvY2ssIGZsYWdzKTsKPj4gKyAgICAgICAgcmV0dXJu IHJldDsKPj4gKyAgICB9Cj4+ICsKPj4gKyAgICByZWcgPSBzZGhjaV9yZWFkbChob3N0LCBTREhD X1NMT1RfRExMX0NVUl9ETFlfVkFMKTsKPj4gKyAgICB0dW5pbmdfc3RlcCA9IHJlZyAvIHBhcmFt cy0+dHVuX3N0ZXBfZGl2aWRlcjsKPj4gKyAgICBpZiAodW5saWtlbHkodHVuaW5nX3N0ZXAgPiBU VU5JTkdfU1RFUF9NQVNLKSkgewo+PiArICAgICAgICBkZXZfd2FybihtbWNfZGV2KGhvc3QtPm1t YyksCj4+ICsgICAgICAgICAgICAgIkhTMjAwIFRVTklOR19TVEVQICVkIGlzIGxhcmdlciB0aGFu IE1BWCB2YWx1ZVxuIiwKPj4gKyAgICAgICAgICAgICB0dW5pbmdfc3RlcCk7Cj4+ICsgICAgICAg IHR1bmluZ19zdGVwID0gVFVOSU5HX1NURVBfTUFTSzsKPj4gKyAgICB9Cj4+ICsKPj4gKyAgICBy ZWcgPSBzZGhjaV9yZWFkbChob3N0LCBTREhDX1NMT1RfT1BfU1RBVFVTX0NUUkwpOwo+PiArICAg IHJlZyAmPSB+KFRVTl9DT05TRUNVVElWRV9USU1FU19NQVNLIDw8IFRVTl9DT05TRUNVVElWRV9U SU1FU19TSElGVCk7Cj4+ICsgICAgcmVnIHw9IChwYXJhbXMtPm5yX3R1bl90aW1lcyA8PCBUVU5f Q09OU0VDVVRJVkVfVElNRVNfU0hJRlQpOwo+PiArICAgIHJlZyAmPSB+KFRVTklOR19TVEVQX01B U0sgPDwgVFVOSU5HX1NURVBfU0hJRlQpOwo+PiArICAgIHJlZyB8PSAodHVuaW5nX3N0ZXAgPDwg VFVOSU5HX1NURVBfU0hJRlQpOwo+PiArICAgIHNkaGNpX3dyaXRlbChob3N0LCByZWcsIFNESENf U0xPVF9PUF9TVEFUVVNfQ1RSTCk7Cj4+ICsKPj4gKyAgICBzcGluX3VubG9ja19pcnFyZXN0b3Jl KCZob3N0LT5sb2NrLCBmbGFncyk7Cj4+ICsgICAgcmV0dXJuIDA7Cj4+ICt9Cj4+ICsKPj4gK3N0 YXRpYyBpbnQgeGVub25fZW1tY19waHlfY29uZmlnX3R1bmluZyhzdHJ1Y3Qgc2RoY2lfaG9zdCAq aG9zdCkKPj4gK3sKPj4gKyAgICByZXR1cm4gX19lbW1jX3BoeV9jb25maWdfdHVuaW5nKGhvc3Qp Owo+PiArfQo+PiArCj4+ICtzdGF0aWMgdm9pZCB4ZW5vbl9lbW1jX3BoeV9zdHJvYmVfZGVsYXlf YWRqKHN0cnVjdCBzZGhjaV9ob3N0ICpob3N0LAo+PiArICAgICAgICAgICAgICAgICAgICAgICAg c3RydWN0IG1tY19jYXJkICpjYXJkKQo+PiArewo+PiArICAgIHUzMiByZWc7Cj4+ICsgICAgc3Ry dWN0IHNkaGNpX3BsdGZtX2hvc3QgKnBsdGZtX2hvc3QgPSBzZGhjaV9wcml2KGhvc3QpOwo+PiAr ICAgIHN0cnVjdCBzZGhjaV94ZW5vbl9wcml2ICpwcml2ID0gc2RoY2lfcGx0Zm1fcHJpdihwbHRm bV9ob3N0KTsKPj4gKyAgICB1bnNpZ25lZCBsb25nIGZsYWdzOwo+PiArCj4+ICsgICAgaWYgKGhv c3QtPmNsb2NrIDw9IE1NQ19ISUdIXzUyX01BWF9EVFIpCj4+ICsgICAgICAgIHJldHVybjsKPj4g Kwo+PiArICAgIGRldl9kYmcobW1jX2Rldihob3N0LT5tbWMpLCAic3RhcnRzIEhTNDAwIHN0cm9i ZSBkZWxheSBhZGp1c3RtZW50XG4iKTsKPj4gKwo+PiArICAgIHNwaW5fbG9ja19pcnFzYXZlKCZo b3N0LT5sb2NrLCBmbGFncyk7Cj4+ICsKPj4gKyAgICB4ZW5vbl9lbW1jX3BoeV9lbmFibGVfZGxs KGhvc3QpOwo+PiArCj4+ICsgICAgLyogRW5hYmxlIFNESEMgRGF0YSBTdHJvYmUgKi8KPj4gKyAg ICByZWcgPSBzZGhjaV9yZWFkbChob3N0LCBTREhDX1NMT1RfRU1NQ19DVFJMKTsKPj4gKyAgICBy ZWcgfD0gRU5BQkxFX0RBVEFfU1RST0JFOwo+PiArICAgIHNkaGNpX3dyaXRlbChob3N0LCByZWcs IFNESENfU0xPVF9FTU1DX0NUUkwpOwo+PiArCj4+ICsgICAgLyogU2V0IERhdGEgU3Ryb2JlIFB1 bGwgZG93biAqLwo+PiArICAgIGlmIChwcml2LT5waHlfdHlwZSA9PSBFTU1DXzVfMF9QSFkpIHsK Pj4gKyAgICAgICAgcmVnID0gc2RoY2lfcmVhZGwoaG9zdCwgRU1NQ181XzBfUEhZX1BBRF9DT05U Uk9MKTsKPj4gKyAgICAgICAgcmVnIHw9IEVNTUM1X0ZDX1FTUF9QRDsKPj4gKyAgICAgICAgcmVn ICY9IH5FTU1DNV9GQ19RU1BfUFU7Cj4+ICsgICAgICAgIHNkaGNpX3dyaXRlbChob3N0LCByZWcs IEVNTUNfNV8wX1BIWV9QQURfQ09OVFJPTCk7Cj4+ICsgICAgfSBlbHNlIHsKPj4gKyAgICAgICAg cmVnID0gc2RoY2lfcmVhZGwoaG9zdCwgRU1NQ19QSFlfUEFEX0NPTlRST0wxKTsKPj4gKyAgICAg ICAgcmVnIHw9IEVNTUM1XzFfRkNfUVNQX1BEOwo+PiArICAgICAgICByZWcgJj0gfkVNTUM1XzFf RkNfUVNQX1BVOwo+PiArICAgICAgICBzZGhjaV93cml0ZWwoaG9zdCwgcmVnLCBFTU1DX1BIWV9Q QURfQ09OVFJPTDEpOwo+PiArICAgIH0KPj4gKyAgICBzcGluX3VubG9ja19pcnFyZXN0b3JlKCZo b3N0LT5sb2NrLCBmbGFncyk7Cj4+ICt9Cj4+ICsKPj4gKyNkZWZpbmUgTE9HSUNfVElNSU5HX1ZB TFVFICAgIDB4MDBBQTg5NzcKPj4gKwo+PiArc3RhdGljIHZvaWQgeGVub25fZW1tY19waHlfc2V0 KHN0cnVjdCBzZGhjaV9ob3N0ICpob3N0LAo+PiArICAgICAgICAgICAgICAgICAgIHVuc2lnbmVk IGNoYXIgdGltaW5nKQo+PiArewo+PiArICAgIHUzMiByZWc7Cj4+ICsgICAgc3RydWN0IHNkaGNp X3BsdGZtX2hvc3QgKnBsdGZtX2hvc3QgPSBzZGhjaV9wcml2KGhvc3QpOwo+PiArICAgIHN0cnVj dCBzZGhjaV94ZW5vbl9wcml2ICpwcml2ID0gc2RoY2lfcGx0Zm1fcHJpdihwbHRmbV9ob3N0KTsK Pj4gKyAgICBzdHJ1Y3QgZW1tY19waHlfcGFyYW1zICpwYXJhbXMgPSBwcml2LT5waHlfcGFyYW1z Owo+PiArICAgIHN0cnVjdCB4ZW5vbl9lbW1jX3BoeV9yZWdzICpwaHlfcmVncyA9IHByaXYtPmVt bWNfcGh5X3JlZ3M7Cj4+ICsgICAgc3RydWN0IG1tY19jYXJkICpjYXJkID0gcHJpdi0+Y2FyZF9j YW5kaWRhdGU7Cj4+ICsgICAgdW5zaWduZWQgbG9uZyBmbGFnczsKPj4gKwo+PiArICAgIGRldl9k YmcobW1jX2Rldihob3N0LT5tbWMpLCAiZU1NQyBQSFkgc2V0dGluZyBzdGFydHNcbiIpOwo+PiAr Cj4+ICsgICAgc3Bpbl9sb2NrX2lycXNhdmUoJmhvc3QtPmxvY2ssIGZsYWdzKTsKPj4gKwo+PiAr ICAgIC8qIFNldHVwIHBhZCwgc2V0IGJpdFsyOF0gYW5kIGJpdHNbMjY6MjRdICovCj4+ICsgICAg cmVnID0gc2RoY2lfcmVhZGwoaG9zdCwgcGh5X3JlZ3MtPnBhZF9jdHJsKTsKPj4gKyAgICByZWcg fD0gKEZDX0RRX1JFQ0VOIHwgRkNfQ01EX1JFQ0VOIHwgRkNfUVNQX1JFQ0VOIHwgT0VOX1FTTik7 Cj4+ICsgICAgLyoKPj4gKyAgICAgKiBBbGwgRkNfWFhfUkVDRUlWQ0Ugc2hvdWxkIGJlIHNldCBh cyBDTU9TIFR5cGUKPj4gKyAgICAgKi8KPj4gKyAgICByZWcgfD0gRkNfQUxMX0NNT1NfUkVDRUlW RVI7Cj4+ICsgICAgc2RoY2lfd3JpdGVsKGhvc3QsIHJlZywgcGh5X3JlZ3MtPnBhZF9jdHJsKTsK Pj4gKwo+PiArICAgIC8qIFNldCBDTUQgYW5kIERRIFB1bGwgVXAgKi8KPj4gKyAgICBpZiAocHJp di0+cGh5X3R5cGUgPT0gRU1NQ181XzBfUEhZKSB7Cj4+ICsgICAgICAgIHJlZyA9IHNkaGNpX3Jl YWRsKGhvc3QsIEVNTUNfNV8wX1BIWV9QQURfQ09OVFJPTCk7Cj4+ICsgICAgICAgIHJlZyB8PSAo RU1NQzVfRkNfQ01EX1BVIHwgRU1NQzVfRkNfRFFfUFUpOwo+PiArICAgICAgICByZWcgJj0gfihF TU1DNV9GQ19DTURfUEQgfCBFTU1DNV9GQ19EUV9QRCk7Cj4+ICsgICAgICAgIHNkaGNpX3dyaXRl bChob3N0LCByZWcsIEVNTUNfNV8wX1BIWV9QQURfQ09OVFJPTCk7Cj4+ICsgICAgfSBlbHNlIHsK Pj4gKyAgICAgICAgcmVnID0gc2RoY2lfcmVhZGwoaG9zdCwgRU1NQ19QSFlfUEFEX0NPTlRST0wx KTsKPj4gKyAgICAgICAgcmVnIHw9IChFTU1DNV8xX0ZDX0NNRF9QVSB8IEVNTUM1XzFfRkNfRFFf UFUpOwo+PiArICAgICAgICByZWcgJj0gfihFTU1DNV8xX0ZDX0NNRF9QRCB8IEVNTUM1XzFfRkNf RFFfUEQpOwo+PiArICAgICAgICBzZGhjaV93cml0ZWwoaG9zdCwgcmVnLCBFTU1DX1BIWV9QQURf Q09OVFJPTDEpOwo+PiArICAgIH0KPj4gKwo+PiArICAgIGlmICgodGltaW5nID09IE1NQ19USU1J TkdfTEVHQUNZKSB8fCAhY2FyZCkKPj4gKyAgICAgICAgZ290byBwaHlfaW5pdDsKPj4gKwo+PiAr ICAgIC8qCj4+ICsgICAgICogRklYTUU6IHNob3VsZCBkZXBlbmRzIG9uIHRoZSBzcGVjaWZpYyBi b2FyZCB0aW1pbmcuCj4+ICsgICAgICovCj4+ICsgICAgaWYgKCh0aW1pbmcgPT0gTU1DX1RJTUlO R19NTUNfSFM0MDApIHx8Cj4+ICsgICAgICAgICh0aW1pbmcgPT0gTU1DX1RJTUlOR19NTUNfSFMy MDApIHx8Cj4+ICsgICAgICAgICh0aW1pbmcgPT0gTU1DX1RJTUlOR19VSFNfU0RSNTApIHx8Cj4+ ICsgICAgICAgICh0aW1pbmcgPT0gTU1DX1RJTUlOR19VSFNfU0RSMTA0KSB8fAo+PiArICAgICAg ICAodGltaW5nID09IE1NQ19USU1JTkdfVUhTX0REUjUwKSB8fAo+PiArICAgICAgICAodGltaW5n ID09IE1NQ19USU1JTkdfVUhTX1NEUjI1KSB8fAo+PiArICAgICAgICAodGltaW5nID09IE1NQ19U SU1JTkdfTU1DX0REUjUyKSkgewo+PiArICAgICAgICByZWcgPSBzZGhjaV9yZWFkbChob3N0LCBw aHlfcmVncy0+dGltaW5nX2Fkaik7Cj4+ICsgICAgICAgIHJlZyAmPSB+T1VUUFVUX1FTTl9QSEFT RV9TRUxFQ1Q7Cj4+ICsgICAgICAgIHNkaGNpX3dyaXRlbChob3N0LCByZWcsIHBoeV9yZWdzLT50 aW1pbmdfYWRqKTsKPj4gKyAgICB9Cj4+ICsKPj4gKyAgICAvKgo+PiArICAgICAqIElmIFNESU8g Y2FyZCwgc2V0IFNESU8gTW9kZQo+PiArICAgICAqIE90aGVyd2lzZSwgY2xlYXIgU0RJTyBNb2Rl IGFuZCBTbG93IE1vZGUKPj4gKyAgICAgKi8KPj4gKyAgICBpZiAobW1jX2NhcmRfc2RpbyhjYXJk KSkgewo+PiArICAgICAgICByZWcgPSBzZGhjaV9yZWFkbChob3N0LCBwaHlfcmVncy0+dGltaW5n X2Fkaik7Cj4+ICsgICAgICAgIHJlZyB8PSBUSU1JTkdfQURKVVNUX1NESU9fTU9ERTsKPj4gKwo+ PiArICAgICAgICBpZiAoKHRpbWluZyA9PSBNTUNfVElNSU5HX1VIU19TRFIyNSkgfHwKPj4gKyAg ICAgICAgICAgICh0aW1pbmcgPT0gTU1DX1RJTUlOR19VSFNfU0RSMTIpIHx8Cj4+ICsgICAgICAg ICAgICAodGltaW5nID09IE1NQ19USU1JTkdfU0RfSFMpIHx8Cj4+ICsgICAgICAgICAgICAodGlt aW5nID09IE1NQ19USU1JTkdfTEVHQUNZKSkKPj4gKyAgICAgICAgICAgIHJlZyB8PSBUSU1JTkdf QURKVVNUX1NMT1dfTU9ERTsKPj4gKwo+PiArICAgICAgICBzZGhjaV93cml0ZWwoaG9zdCwgcmVn LCBwaHlfcmVncy0+dGltaW5nX2Fkaik7Cj4+ICsgICAgfSBlbHNlIHsKPj4gKyAgICAgICAgcmVn ID0gc2RoY2lfcmVhZGwoaG9zdCwgcGh5X3JlZ3MtPnRpbWluZ19hZGopOwo+PiArICAgICAgICBy ZWcgJj0gfihUSU1JTkdfQURKVVNUX1NESU9fTU9ERSB8IFRJTUlOR19BREpVU1RfU0xPV19NT0RF KTsKPj4gKyAgICAgICAgc2RoY2lfd3JpdGVsKGhvc3QsIHJlZywgcGh5X3JlZ3MtPnRpbWluZ19h ZGopOwo+PiArICAgIH0KPj4gKwo+PiArICAgIGlmICgoKHRpbWluZyA9PSBNTUNfVElNSU5HX1VI U19TRFI1MCkgfHwKPj4gKyAgICAgICAgICh0aW1pbmcgPT0gTU1DX1RJTUlOR19VSFNfU0RSMjUp IHx8Cj4+ICsgICAgICAgICAodGltaW5nID09IE1NQ19USU1JTkdfVUhTX1NEUjEyKSB8fAo+PiAr ICAgICAgICAgKHRpbWluZyA9PSBNTUNfVElNSU5HX1NEX0hTKSB8fAo+PiArICAgICAgICAgKHRp bWluZyA9PSBNTUNfVElNSU5HX01NQ19IUykgfHwKPj4gKyAgICAgICAgICh0aW1pbmcgPT0gTU1D X1RJTUlOR19MRUdBQ1kpKSAmJiBwYXJhbXMtPnNsb3dfbW9kZSkgewo+PiArICAgICAgICByZWcg PSBzZGhjaV9yZWFkbChob3N0LCBwaHlfcmVncy0+dGltaW5nX2Fkaik7Cj4+ICsgICAgICAgIHJl ZyB8PSBUSU1JTkdfQURKVVNUX1NMT1dfTU9ERTsKPj4gKyAgICAgICAgc2RoY2lfd3JpdGVsKGhv c3QsIHJlZywgcGh5X3JlZ3MtPnRpbWluZ19hZGopOwo+PiArICAgIH0KPj4gKwo+PiArICAgIC8q Cj4+ICsgICAgICogU2V0IHByZWZlcnJlZCBaTlIgYW5kIFpQUiB2YWx1ZQo+PiArICAgICAqIFRo ZSBaTlIgYW5kIFpQUiB2YWx1ZSB2YXJ5IGJldHdlZW4gZGlmZmVyZW50IGJvYXJkcy4KPj4gKyAg ICAgKiBEZWZpbmUgdGhlbSBib3RoIGluIHNkaGNpLXhlbm9uLWVtbWMtcGh5LmguCj4+ICsgICAg ICovCj4+ICsgICAgcmVnID0gc2RoY2lfcmVhZGwoaG9zdCwgcGh5X3JlZ3MtPnBhZF9jdHJsMik7 Cj4+ICsgICAgcmVnICY9IH4oKFpOUl9NQVNLIDw8IFpOUl9TSElGVCkgfCBaUFJfTUFTSyk7Cj4+ ICsgICAgcmVnIHw9ICgocGFyYW1zLT56bnIgPDwgWk5SX1NISUZUKSB8IHBhcmFtcy0+enByKTsK Pj4gKyAgICBzZGhjaV93cml0ZWwoaG9zdCwgcmVnLCBwaHlfcmVncy0+cGFkX2N0cmwyKTsKPj4g Kwo+PiArICAgIC8qCj4+ICsgICAgICogV2hlbiBzZXR0aW5nIEVNTUNfUEhZX0ZVTkNfQ09OVFJP TCByZWdpc3RlciwKPj4gKyAgICAgKiBTRCBjbG9jayBzaG91bGQgYmUgZGlzYWJsZWQKPj4gKyAg ICAgKi8KPj4gKyAgICByZWcgPSBzZGhjaV9yZWFkbChob3N0LCBTREhDSV9DTE9DS19DT05UUk9M KTsKPj4gKyAgICByZWcgJj0gflNESENJX0NMT0NLX0NBUkRfRU47Cj4+ICsgICAgc2RoY2lfd3Jp dGV3KGhvc3QsIHJlZywgU0RIQ0lfQ0xPQ0tfQ09OVFJPTCk7Cj4+ICsKPj4gKyAgICBpZiAoKHRp bWluZyA9PSBNTUNfVElNSU5HX1VIU19ERFI1MCkgfHwKPj4gKyAgICAgICAgKHRpbWluZyA9PSBN TUNfVElNSU5HX01NQ19IUzQwMCkgfHwKPj4gKyAgICAgICAgKHRpbWluZyA9PSBNTUNfVElNSU5H X01NQ19ERFI1MikpIHsKPj4gKyAgICAgICAgcmVnID0gc2RoY2lfcmVhZGwoaG9zdCwgcGh5X3Jl Z3MtPmZ1bmNfY3RybCk7Cj4+ICsgICAgICAgIHJlZyB8PSAoRFFfRERSX01PREVfTUFTSyA8PCBE UV9ERFJfTU9ERV9TSElGVCkgfCBDTURfRERSX01PREU7Cj4+ICsgICAgICAgIHNkaGNpX3dyaXRl bChob3N0LCByZWcsIHBoeV9yZWdzLT5mdW5jX2N0cmwpOwo+PiArICAgIH0KPj4gKwo+PiArICAg IGlmICh0aW1pbmcgPT0gTU1DX1RJTUlOR19NTUNfSFM0MDApIHsKPj4gKyAgICAgICAgcmVnID0g c2RoY2lfcmVhZGwoaG9zdCwgcGh5X3JlZ3MtPmZ1bmNfY3RybCk7Cj4+ICsgICAgICAgIHJlZyAm PSB+RFFfQVNZTkNfTU9ERTsKPj4gKyAgICAgICAgc2RoY2lfd3JpdGVsKGhvc3QsIHJlZywgcGh5 X3JlZ3MtPmZ1bmNfY3RybCk7Cj4+ICsgICAgfQo+PiArCj4+ICsgICAgLyogRW5hYmxlIGJ1cyBj bG9jayAqLwo+PiArICAgIHJlZyA9IHNkaGNpX3JlYWRsKGhvc3QsIFNESENJX0NMT0NLX0NPTlRS T0wpOwo+PiArICAgIHJlZyB8PSBTREhDSV9DTE9DS19DQVJEX0VOOwo+PiArICAgIHNkaGNpX3dy aXRldyhob3N0LCByZWcsIFNESENJX0NMT0NLX0NPTlRST0wpOwo+PiArCj4+ICsgICAgaWYgKHRp bWluZyA9PSBNTUNfVElNSU5HX01NQ19IUzQwMCkKPj4gKyAgICAgICAgLyogSGFyZHdhcmUgdGVh bSByZWNvbW1lbmQgYSB2YWx1ZSBmb3IgSFM0MDAgKi8KPj4gKyAgICAgICAgc2RoY2lfd3JpdGVs KGhvc3QsIExPR0lDX1RJTUlOR19WQUxVRSwKPj4gKyAgICAgICAgICAgICAgICAgcGh5X3JlZ3Mt PmxvZ2ljX3RpbWluZ19hZGopOwo+PiArCj4+ICtwaHlfaW5pdDoKPj4gKyAgICB4ZW5vbl9lbW1j X3BoeV9pbml0KGhvc3QpOwo+PiArCj4+ICsgICAgc3Bpbl91bmxvY2tfaXJxcmVzdG9yZSgmaG9z dC0+bG9jaywgZmxhZ3MpOwo+PiArCj4+ICsgICAgZGV2X2RiZyhtbWNfZGV2KGhvc3QtPm1tYyks ICJlTU1DIFBIWSBzZXR0aW5nIGNvbXBsZXRlc1xuIik7Cj4+ICt9Cj4+ICsKPj4gK3N0YXRpYyBp bnQgZ2V0X2R0X3BhZF9jdHJsX2RhdGEoc3RydWN0IHNkaGNpX2hvc3QgKmhvc3QsCj4+ICsgICAg ICAgICAgICAgICAgc3RydWN0IGRldmljZV9ub2RlICpucCwKPj4gKyAgICAgICAgICAgICAgICBz dHJ1Y3QgZW1tY19waHlfcGFyYW1zICpwYXJhbXMpCj4+ICt7Cj4+ICsgICAgaW50IHJldCA9IDA7 Cj4+ICsgICAgY29uc3QgY2hhciAqbmFtZTsKPj4gKyAgICBzdHJ1Y3QgcmVzb3VyY2UgaW9tZW07 Cj4+ICsKPj4gKyAgICBpZiAob2ZfZGV2aWNlX2lzX2NvbXBhdGlibGUobnAsICJtYXJ2ZWxsLGFy bWFkYS0zNzAwLXNkaGNpIikpCj4+ICsgICAgICAgIHBhcmFtcy0+cGFkX2N0cmwuc2V0X3NvY19w YWQgPSBhcm1hZGFfMzcwMF9zb2NfcGFkX3ZvbHRhZ2Vfc2V0Owo+PiArICAgIGVsc2UKPj4gKyAg ICAgICAgcmV0dXJuIDA7Cj4+ICsKPj4gKyAgICBpZiAob2ZfYWRkcmVzc190b19yZXNvdXJjZShu cCwgMSwgJmlvbWVtKSkgewo+PiArICAgICAgICBkZXZfZXJyKG1tY19kZXYoaG9zdC0+bW1jKSwg IlVuYWJsZSB0byBmaW5kIFNPQyBQQUQgY3RybCByZWdpc3RlciBhZGRyZXNzIGZvciAlc1xuIiwK Pj4gKyAgICAgICAgICAgIG5wLT5uYW1lKTsKPj4gKyAgICAgICAgcmV0dXJuIC1FSU5WQUw7Cj4+ ICsgICAgfQo+PiArCj4+ICsgICAgcGFyYW1zLT5wYWRfY3RybC5yZWcgPSBkZXZtX2lvcmVtYXBf cmVzb3VyY2UobW1jX2Rldihob3N0LT5tbWMpLAo+PiArICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAmaW9tZW0pOwo+PiArICAgIGlmIChJU19FUlIocGFyYW1zLT5wYWRfY3RybC5yZWcpKSB7 Cj4+ICsgICAgICAgIGRldl9lcnIobW1jX2Rldihob3N0LT5tbWMpLCAiVW5hYmxlIHRvIGdldCBT T0MgUEhZIFBBRCBjdHJsIHJlZ2lzZXIgZm9yICVzXG4iLAo+PiArICAgICAgICAgICAgbnAtPm5h bWUpOwo+PiArICAgICAgICByZXR1cm4gUFRSX0VSUihwYXJhbXMtPnBhZF9jdHJsLnJlZyk7Cj4+ ICsgICAgfQo+PiArCj4+ICsgICAgcmV0ID0gb2ZfcHJvcGVydHlfcmVhZF9zdHJpbmcobnAsICJ4 ZW5vbixwYWQtdHlwZSIsICZuYW1lKTsKPj4gKyAgICBpZiAocmV0KSB7Cj4+ICsgICAgICAgIGRl dl9lcnIobW1jX2Rldihob3N0LT5tbWMpLCAiVW5hYmxlIHRvIGRldGVybWluZSBTT0MgUEhZIFBB RCBjdHJsIHR5cGVcbiIpOwo+PiArICAgICAgICByZXR1cm4gcmV0Owo+PiArICAgIH0KPj4gKyAg ICBpZiAoIXN0cmNtcChuYW1lLCAic2QiKSkgewo+PiArICAgICAgICBwYXJhbXMtPnBhZF9jdHJs LnBhZF90eXBlID0gU09DX1BBRF9TRDsKPj4gKyAgICB9IGVsc2UgaWYgKCFzdHJjbXAobmFtZSwg ImZpeGVkLTEtOHYiKSkgewo+PiArICAgICAgICBwYXJhbXMtPnBhZF9jdHJsLnBhZF90eXBlID0g U09DX1BBRF9GSVhFRF8xXzhWOwo+PiArICAgIH0gZWxzZSB7Cj4+ICsgICAgICAgIGRldl9lcnIo bW1jX2Rldihob3N0LT5tbWMpLCAiVW5zdXBwb3J0ZWQgU09DIFBIWSBQQUQgY3RybCB0eXBlICVz XG4iLAo+PiArICAgICAgICAgICAgbmFtZSk7Cj4+ICsgICAgICAgIHJldHVybiAtRUlOVkFMOwo+ PiArICAgIH0KPj4gKwo+PiArICAgIHJldHVybiByZXQ7Cj4+ICt9Cj4+ICsKPj4gK3N0YXRpYyBp bnQgZW1tY19waHlfcGFyc2VfcGFyYW1fZHQoc3RydWN0IHNkaGNpX2hvc3QgKmhvc3QsCj4+ICsg ICAgICAgICAgICAgICAgICAgc3RydWN0IGRldmljZV9ub2RlICpucCwKPj4gKyAgICAgICAgICAg ICAgICAgICBzdHJ1Y3QgZW1tY19waHlfcGFyYW1zICpwYXJhbXMpCj4+ICt7Cj4+ICsgICAgdTMy IHZhbHVlOwo+PiArCj4+ICsgICAgaWYgKG9mX3Byb3BlcnR5X3JlYWRfYm9vbChucCwgInhlbm9u LHBoeS1zbG93LW1vZGUiKSkKPj4gKyAgICAgICAgcGFyYW1zLT5zbG93X21vZGUgPSB0cnVlOwo+ PiArICAgIGVsc2UKPj4gKyAgICAgICAgcGFyYW1zLT5zbG93X21vZGUgPSBmYWxzZTsKPj4gKwo+ PiArICAgIGlmICghb2ZfcHJvcGVydHlfcmVhZF91MzIobnAsICJ4ZW5vbixwaHktem5yIiwgJnZh bHVlKSkKPj4gKyAgICAgICAgcGFyYW1zLT56bnIgPSB2YWx1ZSAmIFpOUl9NQVNLOwo+PiArICAg IGVsc2UKPj4gKyAgICAgICAgcGFyYW1zLT56bnIgPSBaTlJfREVGX1ZBTFVFOwo+PiArCj4+ICsg ICAgaWYgKCFvZl9wcm9wZXJ0eV9yZWFkX3UzMihucCwgInhlbm9uLHBoeS16cHIiLCAmdmFsdWUp KQo+PiArICAgICAgICBwYXJhbXMtPnpwciA9IHZhbHVlICYgWlBSX01BU0s7Cj4+ICsgICAgZWxz ZQo+PiArICAgICAgICBwYXJhbXMtPnpwciA9IFpQUl9ERUZfVkFMVUU7Cj4+ICsKPj4gKyAgICBp ZiAoIW9mX3Byb3BlcnR5X3JlYWRfdTMyKG5wLCAieGVub24scGh5LW5yLXR1bi10aW1lcyIsICZ2 YWx1ZSkpCj4+ICsgICAgICAgIHBhcmFtcy0+bnJfdHVuX3RpbWVzID0gdmFsdWUgJiBUVU5fQ09O U0VDVVRJVkVfVElNRVNfTUFTSzsKPj4gKyAgICBlbHNlCj4+ICsgICAgICAgIHBhcmFtcy0+bnJf dHVuX3RpbWVzID0gVFVOX0NPTlNFQ1VUSVZFX1RJTUVTOwo+PiArCj4+ICsgICAgaWYgKCFvZl9w cm9wZXJ0eV9yZWFkX3UzMihucCwgInhlbm9uLHBoeS10dW4tc3RlcC1kaXZpZGVyIiwgJnZhbHVl KSkKPj4gKyAgICAgICAgcGFyYW1zLT50dW5fc3RlcF9kaXZpZGVyID0gdmFsdWUgJiAweEZGOwo+ PiArICAgIGVsc2UKPj4gKyAgICAgICAgcGFyYW1zLT50dW5fc3RlcF9kaXZpZGVyID0gVFVOSU5H X1NURVBfRElWSURFUjsKPj4gKwo+PiArICAgIHJldHVybiBnZXRfZHRfcGFkX2N0cmxfZGF0YSho b3N0LCBucCwgcGFyYW1zKTsKPj4gK30KPj4gKwo+PiArLyoKPj4gKyAqIFNESCBQSFkgY29uZmln dXJhdGlvbiBhbmQgb3BlcmF0aW9ucwo+PiArICovCj4+ICtzdGF0aWMgaW50IHhlbm9uX3NkaF9w aHlfc2V0X2ZpeF9zYW1wbF9kZWxheShzdHJ1Y3Qgc2RoY2lfaG9zdCAqaG9zdCwKPj4gKyAgICAg ICAgICAgICAgICAgICAgICAgICB1bnNpZ25lZCBpbnQgZGVsYXksIGJvb2wgaW52ZXJ0KQo+PiAr ewo+PiArICAgIHUzMiByZWc7Cj4+ICsgICAgdW5zaWduZWQgbG9uZyBmbGFnczsKPj4gKyAgICBp bnQgcmV0Owo+PiArCj4+ICsgICAgaWYgKGludmVydCkKPj4gKyAgICAgICAgaW52ZXJ0ID0gMHgx Owo+PiArICAgIGVsc2UKPj4gKyAgICAgICAgaW52ZXJ0ID0gMHgwOwo+PiArCj4+ICsgICAgc3Bp bl9sb2NrX2lycXNhdmUoJmhvc3QtPmxvY2ssIGZsYWdzKTsKPj4gKwo+PiArICAgIC8qIERpc2Fi bGUgU0RDTEsgKi8KPj4gKyAgICByZWcgPSBzZGhjaV9yZWFkbChob3N0LCBTREhDSV9DTE9DS19D T05UUk9MKTsKPj4gKyAgICByZWcgJj0gfihTREhDSV9DTE9DS19DQVJEX0VOIHwgU0RIQ0lfQ0xP Q0tfSU5UX0VOKTsKPj4gKyAgICBzZGhjaV93cml0ZWwoaG9zdCwgcmVnLCBTREhDSV9DTE9DS19D T05UUk9MKTsKPj4gKwo+PiArICAgIHVkZWxheSgyMDApOwo+PiArCj4+ICsgICAgLyogU2V0dXAg U2FtcGxpbmcgZml4IGRlbGF5ICovCj4+ICsgICAgcmVnID0gc2RoY2lfcmVhZGwoaG9zdCwgU0RI Q19TTE9UX09QX1NUQVRVU19DVFJMKTsKPj4gKyAgICByZWcgJj0gfihTREhfUEhZX0ZJWEVEX0RF TEFZX01BU0sgfAo+PiArICAgICAgICAgICAgKDB4MSA8PCBGT1JDRV9TRUxfSU5WRVJTRV9DTEtf U0hJRlQpKTsKPj4gKyAgICByZWcgfD0gKChkZWxheSAmIFNESF9QSFlfRklYRURfREVMQVlfTUFT SykgfAo+PiArICAgICAgICAgICAgKGludmVydCA8PCBGT1JDRV9TRUxfSU5WRVJTRV9DTEtfU0hJ RlQpKTsKPj4gKyAgICBzZGhjaV93cml0ZWwoaG9zdCwgcmVnLCBTREhDX1NMT1RfT1BfU1RBVFVT X0NUUkwpOwo+PiArCj4+ICsgICAgLyogRW5hYmxlIFNEIGludGVybmFsIGNsb2NrICovCj4+ICsg ICAgcmV0ID0gZW5hYmxlX3hlbm9uX2ludGVybmFsX2Nsayhob3N0KTsKPj4gKwo+PiArICAgIC8q IEVuYWJsZSBTRENMSyAqLwo+PiArICAgIHJlZyA9IHNkaGNpX3JlYWRsKGhvc3QsIFNESENJX0NM T0NLX0NPTlRST0wpOwo+PiArICAgIHJlZyB8PSBTREhDSV9DTE9DS19DQVJEX0VOOwo+PiArICAg IHNkaGNpX3dyaXRlbChob3N0LCByZWcsIFNESENJX0NMT0NLX0NPTlRST0wpOwo+PiArCj4+ICsg ICAgdWRlbGF5KDIwMCk7Cj4+ICsKPj4gKyAgICBzcGluX3VubG9ja19pcnFyZXN0b3JlKCZob3N0 LT5sb2NrLCBmbGFncyk7Cj4+ICsgICAgcmV0dXJuIHJldDsKPj4gK30KPj4gKwo+PiArc3RhdGlj IGludCBzZGhfcGh5X2RvX2ZpeF9zYW1wbF9kZWxheShzdHJ1Y3Qgc2RoY2lfaG9zdCAqaG9zdCwK Pj4gKyAgICAgICAgICAgICAgICAgICAgICBzdHJ1Y3QgbW1jX2NhcmQgKmNhcmQsCj4+ICsgICAg ICAgICAgICAgICAgICAgICAgdW5zaWduZWQgaW50IGRlbGF5LCBib29sIGludmVydCkKPj4gK3sK Pj4gKyAgICBpbnQgcmV0Owo+PiArCj4+ICsgICAgeGVub25fc2RoX3BoeV9zZXRfZml4X3NhbXBs X2RlbGF5KGhvc3QsIGRlbGF5LCBpbnZlcnQpOwo+PiArCj4+ICsgICAgcmV0ID0geGVub25fZGVs YXlfYWRqX3Rlc3QoY2FyZCk7Cj4+ICsgICAgaWYgKHJldCkgewo+PiArICAgICAgICBkZXZfZGJn KG1tY19kZXYoaG9zdC0+bW1jKSwKPj4gKyAgICAgICAgICAgICJmYWlsIHdoZW4gc2FtcGxpbmcg Zml4IGRlbGF5ID0gJWQsIHBoYXNlID0gJWQgZGVncmVlXG4iLAo+PiArICAgICAgICAgICAgZGVs YXksIGludmVydCAqIDE4MCk7Cj4+ICsgICAgICAgIHJldHVybiAtMTsKPj4gKyAgICB9Cj4+ICsg ICAgcmV0dXJuIDA7Cj4+ICt9Cj4+ICsKPj4gKyNkZWZpbmUgU0RIX1BIWV9DT0FSU0VfRklYX0RF TEFZICAgIChTREhfUEhZX0ZJWEVEX0RFTEFZX01BU0sgLyAyKQo+PiArI2RlZmluZSBTREhfUEhZ X0ZJTkVfRklYX0RFTEFZICAgICAgICAoU0RIX1BIWV9DT0FSU0VfRklYX0RFTEFZIC8gNCkKPj4g Kwo+PiArc3RhdGljIGludCB4ZW5vbl9zZGhfcGh5X2ZpeF9zYW1wbF9kZWxheV9hZGooc3RydWN0 IHNkaGNpX2hvc3QgKmhvc3QsCj4+ICsgICAgICAgICAgICAgICAgICAgICAgICAgc3RydWN0IG1t Y19jYXJkICpjYXJkKQo+PiArewo+PiArICAgIHUzMiByZWc7Cj4+ICsgICAgYm9vbCBkbGxfZW5h YmxlID0gZmFsc2U7Cj4+ICsgICAgdW5zaWduZWQgaW50IG1pbl9kZWxheSwgbWF4X2RlbGF5LCBk ZWxheTsKPj4gKyAgICBjb25zdCBib29sIHNhbXBsX2VkZ2VbXSA9IHsKPj4gKyAgICAgICAgZmFs c2UsCj4+ICsgICAgICAgIHRydWUsCj4+ICsgICAgfTsKPj4gKyAgICBpbnQgaSwgbnI7Cj4+ICsg ICAgaW50IHJldDsKPj4gKwo+PiArICAgIGlmIChob3N0LT5jbG9jayA+IEhJR0hfU1BFRURfTUFY X0RUUikgewo+PiArICAgICAgICAvKiBFbmFibGUgRExMIHdoZW4gU0RDTEsgaXMgaGlnaGVyIHRo YW4gNTBNSHogKi8KPj4gKyAgICAgICAgcmVnID0gc2RoY2lfcmVhZGwoaG9zdCwgU0RIX1BIWV9T TE9UX0RMTF9DVFJMKTsKPj4gKyAgICAgICAgaWYgKCEocmVnICYgU0RIX1BIWV9FTkFCTEVfRExM KSkgewo+PiArICAgICAgICAgICAgcmVnIHw9IChTREhfUEhZX0VOQUJMRV9ETEwgfCBTREhfUEhZ X0ZBU1RfTE9DS19FTik7Cj4+ICsgICAgICAgICAgICBzZGhjaV93cml0ZWwoaG9zdCwgcmVnLCBT REhfUEhZX1NMT1RfRExMX0NUUkwpOwo+PiArICAgICAgICAgICAgbWRlbGF5KDEpOwo+PiArCj4+ ICsgICAgICAgICAgICByZWcgPSBzZGhjaV9yZWFkbChob3N0LCBTREhfUEhZX1NMT1RfRExMX1BI QVNFX1NFTCk7Cj4+ICsgICAgICAgICAgICByZWcgfD0gU0RIX1BIWV9ETExfVVBEQVRFX1RVTklO RzsKPj4gKyAgICAgICAgICAgIHNkaGNpX3dyaXRlbChob3N0LCByZWcsIFNESF9QSFlfU0xPVF9E TExfUEhBU0VfU0VMKTsKPj4gKyAgICAgICAgfQo+PiArICAgICAgICBkbGxfZW5hYmxlID0gdHJ1 ZTsKPj4gKyAgICB9Cj4+ICsKPj4gKyAgICBuciA9IGRsbF9lbmFibGUgPyBBUlJBWV9TSVpFKHNh bXBsX2VkZ2UpIDogMTsKPj4gKyAgICBmb3IgKGkgPSAwOyBpIDwgbnI7IGkrKykgewo+PiArICAg ICAgICBmb3IgKG1pbl9kZWxheSA9IDA7IG1pbl9kZWxheSA8PSBTREhfUEhZX0ZJWEVEX0RFTEFZ X01BU0s7Cj4+ICsgICAgICAgICAgICAgICAgbWluX2RlbGF5ICs9IFNESF9QSFlfQ09BUlNFX0ZJ WF9ERUxBWSkgewo+PiArICAgICAgICAgICAgcmV0ID0gc2RoX3BoeV9kb19maXhfc2FtcGxfZGVs YXkoaG9zdCwgY2FyZCwgbWluX2RlbGF5LAo+PiArICAgICAgICAgICAgICAgICAgICAgICAgICAg ICBzYW1wbF9lZGdlW2ldKTsKPj4gKyAgICAgICAgICAgIGlmICghcmV0KQo+PiArICAgICAgICAg ICAgICAgIGJyZWFrOwo+PiArICAgICAgICB9Cj4+ICsKPj4gKyAgICAgICAgaWYgKHJldCkgewo+ PiArICAgICAgICAgICAgZGV2X2RiZyhtbWNfZGV2KGhvc3QtPm1tYyksCj4+ICsgICAgICAgICAg ICAgICAgIkZhaWwgdG8gc2V0IEZpeGVkIFNhbXBsaW5nIERlbGF5IHdpdGggJXMgZWRnZVxuIiwK Pj4gKyAgICAgICAgICAgICAgICBzYW1wbF9lZGdlW2ldID8gIm5lZ2F0aXZlIiA6ICJwb3NpdGl2 ZSIpOwo+PiArICAgICAgICAgICAgY29udGludWU7Cj4+ICsgICAgICAgIH0KPj4gKwo+PiArICAg ICAgICBmb3IgKG1heF9kZWxheSA9IG1pbl9kZWxheSArIFNESF9QSFlfRklORV9GSVhfREVMQVk7 Cj4+ICsgICAgICAgICAgICAgICAgbWF4X2RlbGF5IDwgU0RIX1BIWV9GSVhFRF9ERUxBWV9NQVNL Owo+PiArICAgICAgICAgICAgICAgIG1heF9kZWxheSArPSBTREhfUEhZX0ZJTkVfRklYX0RFTEFZ KSB7Cj4+ICsgICAgICAgICAgICByZXQgPSBzZGhfcGh5X2RvX2ZpeF9zYW1wbF9kZWxheShob3N0 LCBjYXJkLCBtYXhfZGVsYXksCj4+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhbXBs X2VkZ2VbaV0pOwo+PiArICAgICAgICAgICAgaWYgKHJldCkgewo+PiArICAgICAgICAgICAgICAg IG1heF9kZWxheSAtPSBTREhfUEhZX0ZJTkVfRklYX0RFTEFZOwo+PiArICAgICAgICAgICAgICAg IGJyZWFrOwo+PiArICAgICAgICAgICAgfQo+PiArICAgICAgICB9Cj4+ICsKPj4gKyAgICAgICAg aWYgKCFyZXQpIHsKPj4gKyAgICAgICAgICAgIGRlbGF5ID0gU0RIX1BIWV9GSVhFRF9ERUxBWV9N QVNLOwo+PiArICAgICAgICAgICAgcmV0ID0gc2RoX3BoeV9kb19maXhfc2FtcGxfZGVsYXkoaG9z dCwgY2FyZCwgZGVsYXksCj4+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhbXBsX2Vk Z2VbaV0pOwo+PiArICAgICAgICAgICAgaWYgKCFyZXQpCj4+ICsgICAgICAgICAgICAgICAgbWF4 X2RlbGF5ID0gU0RIX1BIWV9GSVhFRF9ERUxBWV9NQVNLOwo+PiArICAgICAgICB9Cj4+ICsKPj4g KyAgICAgICAgaWYgKChtYXhfZGVsYXkgLSBtaW5fZGVsYXkpIDw9IFNESF9QSFlfRklYRURfREVM QVlfV0lORE9XX01JTikgewo+PiArICAgICAgICAgICAgZGV2X2luZm8obW1jX2Rldihob3N0LT5t bWMpLAo+PiArICAgICAgICAgICAgICAgICAiVGhlIHdpbmRvdyBzaXplICVkIHdpdGggJXMgZWRn ZSBpcyB0b28gc21hbGxcbiIsCj4+ICsgICAgICAgICAgICAgICAgIG1heF9kZWxheSAtIG1pbl9k ZWxheSwKPj4gKyAgICAgICAgICAgICAgICAgc2FtcGxfZWRnZVtpXSA/ICJuZWdhdGl2ZSIgOiAi cG9zaXRpdmUiKTsKPj4gKyAgICAgICAgICAgIGNvbnRpbnVlOwo+PiArICAgICAgICB9Cj4+ICsK Pj4gKyAgICAgICAgZGVsYXkgPSAobWluX2RlbGF5ICsgbWF4X2RlbGF5KSAvIDI7Cj4+ICsgICAg ICAgIHhlbm9uX3NkaF9waHlfc2V0X2ZpeF9zYW1wbF9kZWxheShob3N0LCBkZWxheSwgc2FtcGxf ZWRnZVtpXSk7Cj4+ICsgICAgICAgIGRldl9kYmcobW1jX2Rldihob3N0LT5tbWMpLCAic2FtcGxp bmcgZml4IGRlbGF5ID0gJWQgd2l0aCAlcyBlZGdlXG4iLAo+PiArICAgICAgICAgICAgZGVsYXks IHNhbXBsX2VkZ2VbaV0gPyAibmVnYXRpdmUiIDogInBvc2l0aXZlIik7Cj4+ICsgICAgICAgIHJl dHVybiAwOwo+PiArICAgIH0KPj4gKyAgICByZXR1cm4gLUVJTzsKPj4gK30KPj4gKwo+PiArc3Rh dGljIGNvbnN0IHN0cnVjdCB4ZW5vbl9waHlfb3BzIHNkaF9waHlfb3BzID0gewo+PiArICAgIC5m aXhfc2FtcGxfZGVsYXlfYWRqID0geGVub25fc2RoX3BoeV9maXhfc2FtcGxfZGVsYXlfYWRqLAo+ PiArfTsKPj4gKwo+PiArc3RhdGljIGludCBhbGxvY19zZGhfcGh5KHN0cnVjdCBzZGhjaV94ZW5v bl9wcml2ICpwcml2KQo+PiArewo+PiArICAgIHByaXYtPnBoeV9wYXJhbXMgPSBOVUxMOwo+PiAr ICAgIHByaXYtPnBoeV9vcHMgPSAmc2RoX3BoeV9vcHM7Cj4+ICsgICAgcmV0dXJuIDA7Cj4+ICt9 Cj4+ICsKPj4gKy8qCj4+ICsgKiBDb21tb24gZnVuY3Rpb25zIGZvciBhbGwgUEhZcwo+PiArICov Cj4+ICt2b2lkIHhlbm9uX3NvY19wYWRfY3RybChzdHJ1Y3Qgc2RoY2lfaG9zdCAqaG9zdCwKPj4g KyAgICAgICAgICAgIHVuc2lnbmVkIGNoYXIgc2lnbmFsX3ZvbHRhZ2UpCj4+ICt7Cj4+ICsgICAg c3RydWN0IHNkaGNpX3BsdGZtX2hvc3QgKnBsdGZtX2hvc3QgPSBzZGhjaV9wcml2KGhvc3QpOwo+ PiArICAgIHN0cnVjdCBzZGhjaV94ZW5vbl9wcml2ICpwcml2ID0gc2RoY2lfcGx0Zm1fcHJpdihw bHRmbV9ob3N0KTsKPj4gKwo+PiArICAgIGlmIChwcml2LT5waHlfb3BzLT5zZXRfc29jX3BhZCkK Pj4gKyAgICAgICAgcHJpdi0+cGh5X29wcy0+c2V0X3NvY19wYWQoaG9zdCwgc2lnbmFsX3ZvbHRh Z2UpOwo+PiArfQo+PiArCj4+ICtzdGF0aWMgaW50IF9feGVub25fZW1tY19kZWxheV9hZGpfdGVz dChzdHJ1Y3QgbW1jX2NhcmQgKmNhcmQpCj4+ICt7Cj4+ICsgICAgaW50IGVycjsKPj4gKyAgICB1 OCAqZXh0X2NzZCA9IE5VTEw7Cj4+ICsKPj4gKyAgICBlcnIgPSBtbWNfZ2V0X2V4dF9jc2QoY2Fy ZCwgJmV4dF9jc2QpOwo+PiArICAgIGtmcmVlKGV4dF9jc2QpOwo+PiArCj4+ICsgICAgcmV0dXJu IGVycjsKPj4gK30KPj4gKwo+PiArc3RhdGljIGludCBfX3hlbm9uX3NkaW9fZGVsYXlfYWRqX3Rl c3Qoc3RydWN0IG1tY19jYXJkICpjYXJkKQo+PiArewo+PiArICAgIHN0cnVjdCBtbWNfY29tbWFu ZCBjbWQgPSB7MH07Cj4+ICsgICAgaW50IGVycjsKPj4gKwo+PiArICAgIGNtZC5vcGNvZGUgPSBT RF9JT19SV19ESVJFQ1Q7Cj4+ICsgICAgY21kLmZsYWdzID0gTU1DX1JTUF9SNSB8IE1NQ19DTURf QUM7Cj4+ICsKPj4gKyAgICBlcnIgPSBtbWNfd2FpdF9mb3JfY21kKGNhcmQtPmhvc3QsICZjbWQs IDApOwo+PiArICAgIGlmIChlcnIpCj4+ICsgICAgICAgIHJldHVybiBlcnI7Cj4+ICsKPj4gKyAg ICBpZiAoY21kLnJlc3BbMF0gJiBSNV9FUlJPUikKPj4gKyAgICAgICAgcmV0dXJuIC1FSU87Cj4+ ICsgICAgaWYgKGNtZC5yZXNwWzBdICYgUjVfRlVOQ1RJT05fTlVNQkVSKQo+PiArICAgICAgICBy ZXR1cm4gLUVJTlZBTDsKPj4gKyAgICBpZiAoY21kLnJlc3BbMF0gJiBSNV9PVVRfT0ZfUkFOR0Up Cj4+ICsgICAgICAgIHJldHVybiAtRVJBTkdFOwo+PiArICAgIHJldHVybiAwOwo+PiArfQo+PiAr Cj4+ICtzdGF0aWMgaW50IF9feGVub25fc2RfZGVsYXlfYWRqX3Rlc3Qoc3RydWN0IG1tY19jYXJk ICpjYXJkKQo+PiArewo+PiArICAgIHN0cnVjdCBtbWNfY29tbWFuZCBjbWQgPSB7MH07Cj4+ICsg ICAgaW50IGVycjsKPj4gKwo+PiArICAgIGNtZC5vcGNvZGUgPSBNTUNfU0VORF9TVEFUVVM7Cj4+ ICsgICAgY21kLmFyZyA9IGNhcmQtPnJjYSA8PCAxNjsKPj4gKyAgICBjbWQuZmxhZ3MgPSBNTUNf UlNQX1IxIHwgTU1DX0NNRF9BQzsKPj4gKwo+PiArICAgIGVyciA9IG1tY193YWl0X2Zvcl9jbWQo Y2FyZC0+aG9zdCwgJmNtZCwgMCk7Cj4+ICsgICAgcmV0dXJuIGVycjsKPj4gK30KPj4gKwo+PiAr c3RhdGljIGludCB4ZW5vbl9kZWxheV9hZGpfdGVzdChzdHJ1Y3QgbW1jX2NhcmQgKmNhcmQpCj4+ ICt7Cj4+ICsgICAgV0FSTl9PTighY2FyZCk7Cj4+ICsgICAgV0FSTl9PTighY2FyZC0+aG9zdCk7 Cj4+ICsKPj4gKyAgICBpZiAobW1jX2NhcmRfbW1jKGNhcmQpKQo+PiArICAgICAgICByZXR1cm4g X194ZW5vbl9lbW1jX2RlbGF5X2Fkal90ZXN0KGNhcmQpOwo+PiArICAgIGVsc2UgaWYgKG1tY19j YXJkX3NkKGNhcmQpKQo+PiArICAgICAgICByZXR1cm4gX194ZW5vbl9zZF9kZWxheV9hZGpfdGVz dChjYXJkKTsKPj4gKyAgICBlbHNlIGlmIChtbWNfY2FyZF9zZGlvKGNhcmQpKQo+PiArICAgICAg ICByZXR1cm4gX194ZW5vbl9zZGlvX2RlbGF5X2Fkal90ZXN0KGNhcmQpOwo+PiArICAgIGVsc2UK Pj4gKyAgICAgICAgcmV0dXJuIC1FSU5WQUw7Cj4+ICt9Cj4+ICsKPj4gK3N0YXRpYyB2b2lkIHhl bm9uX3BoeV9zZXQoc3RydWN0IHNkaGNpX2hvc3QgKmhvc3QsIHVuc2lnbmVkIGNoYXIgdGltaW5n KQo+PiArewo+PiArICAgIHN0cnVjdCBzZGhjaV9wbHRmbV9ob3N0ICpwbHRmbV9ob3N0ID0gc2Ro Y2lfcHJpdihob3N0KTsKPj4gKyAgICBzdHJ1Y3Qgc2RoY2lfeGVub25fcHJpdiAqcHJpdiA9IHNk aGNpX3BsdGZtX3ByaXYocGx0Zm1faG9zdCk7Cj4+ICsKPj4gKyAgICBpZiAocHJpdi0+cGh5X29w cy0+cGh5X3NldCkKPj4gKyAgICAgICAgcHJpdi0+cGh5X29wcy0+cGh5X3NldChob3N0LCB0aW1p bmcpOwo+PiArfQo+PiArCj4+ICtzdGF0aWMgdm9pZCB4ZW5vbl9oczQwMF9zdHJvYmVfZGVsYXlf YWRqKHN0cnVjdCBzZGhjaV9ob3N0ICpob3N0LAo+PiArICAgICAgICAgICAgICAgICAgICAgc3Ry dWN0IG1tY19jYXJkICpjYXJkKQo+PiArewo+PiArICAgIHN0cnVjdCBzZGhjaV9wbHRmbV9ob3N0 ICpwbHRmbV9ob3N0ID0gc2RoY2lfcHJpdihob3N0KTsKPj4gKyAgICBzdHJ1Y3Qgc2RoY2lfeGVu b25fcHJpdiAqcHJpdiA9IHNkaGNpX3BsdGZtX3ByaXYocGx0Zm1faG9zdCk7Cj4+ICsKPj4gKyAg ICBpZiAoV0FSTl9PTighbW1jX2NhcmRfaHM0MDAoY2FyZCkpKQo+PiArICAgICAgICByZXR1cm47 Cj4+ICsKPj4gKyAgICAvKiBFbmFibGUgdGhlIERMTCB0byBhdXRvbWF0aWNhbGx5IGFkanVzdCBI UzQwMCBzdHJvYmUgZGVsYXkuCj4+ICsgICAgICovCj4+ICsgICAgaWYgKHByaXYtPnBoeV9vcHMt PnN0cm9iZV9kZWxheV9hZGopCj4+ICsgICAgICAgIHByaXYtPnBoeV9vcHMtPnN0cm9iZV9kZWxh eV9hZGooaG9zdCwgY2FyZCk7Cj4+ICt9Cj4+ICsKPj4gK3N0YXRpYyBpbnQgeGVub25fZml4X3Nh bXBsX2RlbGF5X2FkaihzdHJ1Y3Qgc2RoY2lfaG9zdCAqaG9zdCwKPj4gKyAgICAgICAgICAgICAg ICAgICAgIHN0cnVjdCBtbWNfY2FyZCAqY2FyZCkKPj4gK3sKPj4gKyAgICBzdHJ1Y3Qgc2RoY2lf cGx0Zm1faG9zdCAqcGx0Zm1faG9zdCA9IHNkaGNpX3ByaXYoaG9zdCk7Cj4+ICsgICAgc3RydWN0 IHNkaGNpX3hlbm9uX3ByaXYgKnByaXYgPSBzZGhjaV9wbHRmbV9wcml2KHBsdGZtX2hvc3QpOwo+ PiArCj4+ICsgICAgaWYgKHByaXYtPnBoeV9vcHMtPmZpeF9zYW1wbF9kZWxheV9hZGopCj4+ICsg ICAgICAgIHJldHVybiBwcml2LT5waHlfb3BzLT5maXhfc2FtcGxfZGVsYXlfYWRqKGhvc3QsIGNh cmQpOwo+PiArCj4+ICsgICAgcmV0dXJuIDA7Cj4+ICt9Cj4+ICsKPj4gKy8qCj4+ICsgKiB4ZW5v bl9kZWxheV9hZGogc2hvdWxkIG5vdCBiZSBjYWxsZWQgaW5zaWRlIElSUSBjb250ZXh0LAo+PiAr ICogZWl0aGVyIEhhcmQgSVJRIG9yIFNvZnRpcnEuCj4+ICsgKi8KPj4gK3N0YXRpYyBpbnQgeGVu b25faHNfZGVsYXlfYWRqKHN0cnVjdCBzZGhjaV9ob3N0ICpob3N0LAo+PiArICAgICAgICAgICAg ICAgICAgc3RydWN0IG1tY19jYXJkICpjYXJkKQo+PiArewo+PiArICAgIHN0cnVjdCBzZGhjaV9w bHRmbV9ob3N0ICpwbHRmbV9ob3N0ID0gc2RoY2lfcHJpdihob3N0KTsKPj4gKyAgICBzdHJ1Y3Qg c2RoY2lfeGVub25fcHJpdiAqcHJpdiA9IHNkaGNpX3BsdGZtX3ByaXYocGx0Zm1faG9zdCk7Cj4+ ICsgICAgaW50IHJldCA9IDA7Cj4+ICsKPj4gKyAgICBpZiAoV0FSTl9PTihob3N0LT5jbG9jayA8 PSBERUZBVUxUX1NEQ0xLX0ZSRVEpKQo+PiArICAgICAgICByZXR1cm4gLUVJTlZBTDsKPj4gKwo+ PiArICAgIGlmIChtbWNfY2FyZF9oczQwMChjYXJkKSkgewo+PiArICAgICAgICB4ZW5vbl9oczQw MF9zdHJvYmVfZGVsYXlfYWRqKGhvc3QsIGNhcmQpOwo+PiArICAgICAgICByZXR1cm4gMDsKPj4g KyAgICB9Cj4+ICsKPj4gKyAgICBpZiAoKChwcml2LT5waHlfdHlwZSA9PSBFTU1DXzVfMV9QSFkp IHx8Cj4+ICsgICAgICAgICAocHJpdi0+cGh5X3R5cGUgPT0gRU1NQ181XzBfUEhZKSkgJiYKPj4g KyAgICAgICAgIChtbWNfY2FyZF9oczIwMChjYXJkKSB8fAo+PiArICAgICAgICAgKGhvc3QtPnRp bWluZyA9PSBNTUNfVElNSU5HX1VIU19TRFIxMDQpKSkgewo+PiArICAgICAgICByZXQgPSB4ZW5v bl9lbW1jX3BoeV9jb25maWdfdHVuaW5nKGhvc3QpOwo+PiArICAgICAgICBpZiAoIXJldCkKPj4g KyAgICAgICAgICAgIHJldHVybiAwOwo+PiArICAgIH0KPj4gKwo+PiArICAgIHJldCA9IHhlbm9u X2ZpeF9zYW1wbF9kZWxheV9hZGooaG9zdCwgY2FyZCk7Cj4+ICsgICAgaWYgKHJldCkKPj4gKyAg ICAgICAgZGV2X2VycihtbWNfZGV2KGhvc3QtPm1tYyksICJmYWlscyBzYW1wbGluZyBmaXhlZCBk ZWxheSBhZGp1c3RtZW50XG4iKTsKPj4gKyAgICByZXR1cm4gcmV0Owo+PiArfQo+PiArCj4+ICtp bnQgeGVub25fcGh5X2FkaihzdHJ1Y3Qgc2RoY2lfaG9zdCAqaG9zdCwgc3RydWN0IG1tY19pb3Mg KmlvcykKPj4gK3sKPj4gKyAgICBzdHJ1Y3QgbW1jX2hvc3QgKm1tYyA9IGhvc3QtPm1tYzsKPj4g KyAgICBzdHJ1Y3QgbW1jX2NhcmQgKmNhcmQ7Cj4+ICsgICAgaW50IHJldCA9IDA7Cj4+ICsgICAg c3RydWN0IHNkaGNpX3BsdGZtX2hvc3QgKnBsdGZtX2hvc3QgPSBzZGhjaV9wcml2KGhvc3QpOwo+ PiArICAgIHN0cnVjdCBzZGhjaV94ZW5vbl9wcml2ICpwcml2ID0gc2RoY2lfcGx0Zm1fcHJpdihw bHRmbV9ob3N0KTsKPj4gKwo+PiArICAgIGlmICghaG9zdC0+Y2xvY2spIHsKPj4gKyAgICAgICAg cHJpdi0+Y2xvY2sgPSAwOwo+PiArICAgICAgICByZXR1cm4gMDsKPj4gKyAgICB9Cj4+ICsKPj4g KyAgICAvKgo+PiArICAgICAqIFRoZSB0aW1pbmcsIGZyZXF1ZW5jeSBvciBidXMgd2lkdGggaXMg Y2hhbmdlZCwKPj4gKyAgICAgKiBiZXR0ZXIgdG8gc2V0IGVNTUMgUEhZIGJhc2VkIG9uIGN1cnJl bnQgc2V0dGluZwo+PiArICAgICAqIGFuZCBhZGp1c3QgWGVub24gU0RIQyBkZWxheS4KPj4gKyAg ICAgKi8KPj4gKyAgICBpZiAoKGhvc3QtPmNsb2NrID09IHByaXYtPmNsb2NrKSAmJgo+PiArICAg ICAgICAoaW9zLT5idXNfd2lkdGggPT0gcHJpdi0+YnVzX3dpZHRoKSAmJgo+PiArICAgICAgICAo aW9zLT50aW1pbmcgPT0gcHJpdi0+dGltaW5nKSkKPj4gKyAgICAgICAgcmV0dXJuIDA7Cj4+ICsK Pj4gKyAgICB4ZW5vbl9waHlfc2V0KGhvc3QsIGlvcy0+dGltaW5nKTsKPj4gKwo+PiArICAgIC8q IFVwZGF0ZSB0aGUgcmVjb3JkICovCj4+ICsgICAgcHJpdi0+YnVzX3dpZHRoID0gaW9zLT5idXNf d2lkdGg7Cj4+ICsgICAgLyogVGVtcCBzdGFnZSBmcm9tIEhTMjAwIHRvIEhTNDAwICovCj4+ICsg ICAgaWYgKCgocHJpdi0+dGltaW5nID09IE1NQ19USU1JTkdfTU1DX0hTMjAwKSAmJgo+PiArICAg ICAgICAgKGlvcy0+dGltaW5nID09IE1NQ19USU1JTkdfTU1DX0hTKSkgfHwKPj4gKyAgICAgICAg KChpb3MtPnRpbWluZyA9PSBNTUNfVElNSU5HX01NQ19IUykgJiYKPj4gKyAgICAgICAgIChwcml2 LT5jbG9jayA+IGhvc3QtPmNsb2NrKSkpIHsKPj4gKyAgICAgICAgcHJpdi0+dGltaW5nID0gaW9z LT50aW1pbmc7Cj4+ICsgICAgICAgIHByaXYtPmNsb2NrID0gaG9zdC0+Y2xvY2s7Cj4+ICsgICAg ICAgIHJldHVybiAwOwo+PiArICAgIH0KPj4gKyAgICBwcml2LT50aW1pbmcgPSBpb3MtPnRpbWlu ZzsKPj4gKyAgICBwcml2LT5jbG9jayA9IGhvc3QtPmNsb2NrOwo+PiArCj4+ICsgICAgLyogTGVn YWN5IG1vZGUgaXMgYSBzcGVjaWFsIGNhc2UgKi8KPj4gKyAgICBpZiAoaW9zLT50aW1pbmcgPT0g TU1DX1RJTUlOR19MRUdBQ1kpCj4+ICsgICAgICAgIHJldHVybiAwOwo+PiArCj4+ICsgICAgY2Fy ZCA9IHByaXYtPmNhcmRfY2FuZGlkYXRlOwo+PiArICAgIGlmICh1bmxpa2VseSghY2FyZCkpIHsK Pj4gKyAgICAgICAgZGV2X3dhcm4obW1jX2RldihtbWMpLCAiY2FyZCBpcyBub3QgcHJlc2VudFxu Iik7Cj4+ICsgICAgICAgIHJldHVybiAtRUlOVkFMOwo+PiArICAgIH0KPj4gKwo+PiArICAgIGlm IChob3N0LT5jbG9jayA+IERFRkFVTFRfU0RDTEtfRlJFUSkKPj4gKyAgICAgICAgcmV0ID0geGVu b25faHNfZGVsYXlfYWRqKGhvc3QsIGNhcmQpOwo+PiArICAgIHJldHVybiByZXQ7Cj4+ICt9Cj4+ ICsKPj4gK3N0YXRpYyBpbnQgYWRkX3hlbm9uX3BoeShzdHJ1Y3QgZGV2aWNlX25vZGUgKm5wLCBz dHJ1Y3Qgc2RoY2lfaG9zdCAqaG9zdCwKPj4gKyAgICAgICAgICAgICBjb25zdCBjaGFyICpwaHlf bmFtZSkKPj4gK3sKPj4gKyAgICBzdHJ1Y3Qgc2RoY2lfcGx0Zm1faG9zdCAqcGx0Zm1faG9zdCA9 IHNkaGNpX3ByaXYoaG9zdCk7Cj4+ICsgICAgc3RydWN0IHNkaGNpX3hlbm9uX3ByaXYgKnByaXYg PSBzZGhjaV9wbHRmbV9wcml2KHBsdGZtX2hvc3QpOwo+PiArICAgIGludCBpLCByZXQ7Cj4+ICsK Pj4gKyAgICBmb3IgKGkgPSAwOyBpIDwgTlJfUEhZX1RZUEVTOyBpKyspIHsKPj4gKyAgICAgICAg aWYgKCFzdHJjbXAocGh5X25hbWUsIHBoeV90eXBlc1tpXSkpIHsKPj4gKyAgICAgICAgICAgIHBy aXYtPnBoeV90eXBlID0gaTsKPj4gKyAgICAgICAgICAgIGJyZWFrOwo+PiArICAgICAgICB9Cj4+ ICsgICAgfQo+PiArICAgIGlmIChpID09IE5SX1BIWV9UWVBFUykgewo+PiArICAgICAgICBkZXZf ZXJyKG1tY19kZXYoaG9zdC0+bW1jKSwKPj4gKyAgICAgICAgICAgICJVbmFibGUgdG8gZGV0ZXJt aW5lIFBIWSBuYW1lICVzLiBVc2UgZGVmYXVsdCBlTU1DIDUuMSBQSFlcbiIsCj4+ICsgICAgICAg ICAgICBwaHlfbmFtZSk7Cj4+ICsgICAgICAgIHByaXYtPnBoeV90eXBlID0gRU1NQ181XzFfUEhZ Owo+PiArICAgIH0KPj4gKwo+PiArICAgIGlmIChwcml2LT5waHlfdHlwZSA9PSBTREhfUEhZKSB7 Cj4+ICsgICAgICAgIHJldHVybiBhbGxvY19zZGhfcGh5KHByaXYpOwo+PiArICAgIH0gZWxzZSBp ZiAoKHByaXYtPnBoeV90eXBlID09IEVNTUNfNV8wX1BIWSkgfHwKPj4gKyAgICAgICAgICAgIChw cml2LT5waHlfdHlwZSA9PSBFTU1DXzVfMV9QSFkpKSB7Cj4+ICsgICAgICAgIHJldCA9IGFsbG9j X2VtbWNfcGh5KHByaXYpOwo+PiArICAgICAgICBpZiAocmV0KQo+PiArICAgICAgICAgICAgcmV0 dXJuIHJldDsKPj4gKyAgICAgICAgcmV0dXJuIGVtbWNfcGh5X3BhcnNlX3BhcmFtX2R0KGhvc3Qs IG5wLCBwcml2LT5waHlfcGFyYW1zKTsKPj4gKyAgICB9Cj4+ICsKPj4gKyAgICByZXR1cm4gLUVJ TlZBTDsKPj4gK30KPj4gKwo+PiAraW50IHhlbm9uX3BoeV9wYXJzZV9kdChzdHJ1Y3QgZGV2aWNl X25vZGUgKm5wLCBzdHJ1Y3Qgc2RoY2lfaG9zdCAqaG9zdCkKPj4gK3sKPj4gKyAgICBjb25zdCBj aGFyICpwaHlfdHlwZSA9IE5VTEw7Cj4+ICsKPj4gKyAgICBpZiAoIW9mX3Byb3BlcnR5X3JlYWRf c3RyaW5nKG5wLCAieGVub24scGh5LXR5cGUiLCAmcGh5X3R5cGUpKQo+PiArICAgICAgICByZXR1 cm4gYWRkX3hlbm9uX3BoeShucCwgaG9zdCwgcGh5X3R5cGUpOwo+PiArCj4+ICsgICAgZGV2X2Vy cihtbWNfZGV2KGhvc3QtPm1tYyksICJGYWlsIHRvIGdldCBYZW5vbiBQSFkgdHlwZS4gVXNlIGRl ZmF1bHQgZU1NQyA1LjEgUEhZXG4iKTsKPj4gKyAgICByZXR1cm4gYWRkX3hlbm9uX3BoeShucCwg aG9zdCwgImVtbWMgNS4xIHBoeSIpOwo+PiArfQo+PiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9tbWMv aG9zdC9zZGhjaS14ZW5vbi1waHkuaCBiL2RyaXZlcnMvbW1jL2hvc3Qvc2RoY2kteGVub24tcGh5 LmgKPj4gbmV3IGZpbGUgbW9kZSAxMDA2NDQKPj4gaW5kZXggMDAwMDAwMDAwMDAwLi40MzczYzcx ZDNiN2IKPj4gLS0tIC9kZXYvbnVsbAo+PiArKysgYi9kcml2ZXJzL21tYy9ob3N0L3NkaGNpLXhl bm9uLXBoeS5oCj4+IEBAIC0wLDAgKzEsMTU3IEBACj4+ICsvKiBsaW51eC9kcml2ZXJzL21tYy9o b3N0L3NkaGNpLXhlbm9uLXBoeS5oCj4+ICsgKgo+PiArICogQXV0aG9yOiAgICBIdSBaaWppIDxo dXppamlAbWFydmVsbC5jb20+Cj4+ICsgKiBEYXRlOiAgICAyMDE2LTgtMjQKPj4gKyAqCj4+ICsg KiAgQ29weXJpZ2h0IChDKSAyMDE2IE1hcnZlbGwsIEFsbCBSaWdodHMgUmVzZXJ2ZWQuCj4+ICsg Kgo+PiArICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmli dXRlIGl0IGFuZC9vciBtb2RpZnkKPj4gKyAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05V IEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5Cj4+ICsgKiB0aGUgRnJlZSBT b2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXIgdmVyc2lvbiAyIG9mIHRoZSBMaWNlbnNlLCBvciAo YXQKPj4gKyAqIHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi4KPj4gKyAqLwo+PiArI2lm bmRlZiBTREhDSV9YRU5PTl9QSFlfSF8KPj4gKyNkZWZpbmUgU0RIQ0lfWEVOT05fUEhZX0hfCj4+ ICsKPj4gKyNpbmNsdWRlIDxsaW51eC90eXBlcy5oPgo+PiArI2luY2x1ZGUgInNkaGNpLmgiCj4+ ICsKPj4gKy8qIFJlZ2lzdGVyIGJhc2UgZm9yIGVNTUMgUEhZIDUuMCBWZXJzaW9uICovCj4+ICsj ZGVmaW5lIEVNTUNfNV8wX1BIWV9SRUdfQkFTRSAgICAgICAgICAgIDB4MDE2MAo+PiArLyogUmVn aXN0ZXIgYmFzZSBmb3IgZU1NQyBQSFkgNS4xIFZlcnNpb24gKi8KPj4gKyNkZWZpbmUgRU1NQ19Q SFlfUkVHX0JBU0UgICAgICAgICAgICAweDAxNzAKPj4gKwo+PiArI2RlZmluZSBFTU1DX1BIWV9U SU1JTkdfQURKVVNUICAgICAgICAgICAgRU1NQ19QSFlfUkVHX0JBU0UKPj4gKyNkZWZpbmUgRU1N Q181XzBfUEhZX1RJTUlOR19BREpVU1QgICAgICAgIEVNTUNfNV8wX1BIWV9SRUdfQkFTRQo+PiAr I2RlZmluZSBUSU1JTkdfQURKVVNUX1NMT1dfTU9ERSAgICAgICAgICAgIEJJVCgyOSkKPj4gKyNk ZWZpbmUgVElNSU5HX0FESlVTVF9TRElPX01PREUgICAgICAgICAgICBCSVQoMjgpCj4+ICsjZGVm aW5lIE9VVFBVVF9RU05fUEhBU0VfU0VMRUNUICAgICAgICAgICAgQklUKDE3KQo+PiArI2RlZmlu ZSBTQU1QTF9JTlZfUVNQX1BIQVNFX1NFTEVDVCAgICAgICAgQklUKDE4KQo+PiArI2RlZmluZSBT QU1QTF9JTlZfUVNQX1BIQVNFX1NFTEVDVF9TSElGVCAgICAxOAo+PiArI2RlZmluZSBQSFlfSU5J VElBTElaQUlPTiAgICAgICAgICAgIEJJVCgzMSkKPj4gKyNkZWZpbmUgV0FJVF9DWUNMRV9CRUZP UkVfVVNJTkdfTUFTSyAgICAgICAgMHhGCj4+ICsjZGVmaW5lIFdBSVRfQ1lDTEVfQkVGT1JFX1VT SU5HX1NISUZUICAgICAgICAxMgo+PiArI2RlZmluZSBGQ19TWU5DX0VOX0RVUkFUSU9OX01BU0sg ICAgICAgIDB4Rgo+PiArI2RlZmluZSBGQ19TWU5DX0VOX0RVUkFUSU9OX1NISUZUICAgICAgICA4 Cj4+ICsjZGVmaW5lIEZDX1NZTkNfUlNUX0VOX0RVUkFUSU9OX01BU0sgICAgICAgIDB4Rgo+PiAr I2RlZmluZSBGQ19TWU5DX1JTVF9FTl9EVVJBVElPTl9TSElGVCAgICAgICAgNAo+PiArI2RlZmlu ZSBGQ19TWU5DX1JTVF9EVVJBVElPTl9NQVNLICAgICAgICAweEYKPj4gKyNkZWZpbmUgRkNfU1lO Q19SU1RfRFVSQVRJT05fU0hJRlQgICAgICAgIDAKPj4gKwo+PiArI2RlZmluZSBFTU1DX1BIWV9G VU5DX0NPTlRST0wgICAgICAgICAgICAoRU1NQ19QSFlfUkVHX0JBU0UgKyAweDQpCj4+ICsjZGVm aW5lIEVNTUNfNV8wX1BIWV9GVU5DX0NPTlRST0wgICAgICAgIChFTU1DXzVfMF9QSFlfUkVHX0JB U0UgKyAweDQpCj4+ICsjZGVmaW5lIEFTWU5DX0REUk1PREVfTUFTSyAgICAgICAgICAgIEJJVCgy MykKPj4gKyNkZWZpbmUgQVNZTkNfRERSTU9ERV9TSElGVCAgICAgICAgICAgIDIzCj4+ICsjZGVm aW5lIENNRF9ERFJfTU9ERSAgICAgICAgICAgICAgICBCSVQoMTYpCj4+ICsjZGVmaW5lIERRX0RE Ul9NT0RFX1NISUZUICAgICAgICAgICAgOAo+PiArI2RlZmluZSBEUV9ERFJfTU9ERV9NQVNLICAg ICAgICAgICAgMHhGRgo+PiArI2RlZmluZSBEUV9BU1lOQ19NT0RFICAgICAgICAgICAgICAgIEJJ VCg0KQo+PiArCj4+ICsjZGVmaW5lIEVNTUNfUEhZX1BBRF9DT05UUk9MICAgICAgICAgICAgKEVN TUNfUEhZX1JFR19CQVNFICsgMHg4KQo+PiArI2RlZmluZSBFTU1DXzVfMF9QSFlfUEFEX0NPTlRS T0wgICAgICAgIChFTU1DXzVfMF9QSFlfUkVHX0JBU0UgKyAweDgpCj4+ICsjZGVmaW5lIFJFQ19F Tl9TSElGVCAgICAgICAgICAgICAgICAyNAo+PiArI2RlZmluZSBSRUNfRU5fTUFTSyAgICAgICAg ICAgICAgICAweEYKPj4gKyNkZWZpbmUgRkNfRFFfUkVDRU4gICAgICAgICAgICAgICAgQklUKDI0 KQo+PiArI2RlZmluZSBGQ19DTURfUkVDRU4gICAgICAgICAgICAgICAgQklUKDI1KQo+PiArI2Rl ZmluZSBGQ19RU1BfUkVDRU4gICAgICAgICAgICAgICAgQklUKDI2KQo+PiArI2RlZmluZSBGQ19R U05fUkVDRU4gICAgICAgICAgICAgICAgQklUKDI3KQo+PiArI2RlZmluZSBPRU5fUVNOICAgICAg ICAgICAgICAgICAgICBCSVQoMjgpCj4+ICsjZGVmaW5lIEFVVE9fUkVDRU5fQ1RSTCAgICAgICAg ICAgICAgICBCSVQoMzApCj4+ICsjZGVmaW5lIEZDX0FMTF9DTU9TX1JFQ0VJVkVSICAgICAgICAg ICAgMHhGMDAwCj4+ICsKPj4gKyNkZWZpbmUgRU1NQzVfRkNfUVNQX1BEICAgICAgICAgICAgICAg IEJJVCgxOCkKPj4gKyNkZWZpbmUgRU1NQzVfRkNfUVNQX1BVICAgICAgICAgICAgICAgIEJJVCgy MikKPj4gKyNkZWZpbmUgRU1NQzVfRkNfQ01EX1BEICAgICAgICAgICAgICAgIEJJVCgxNykKPj4g KyNkZWZpbmUgRU1NQzVfRkNfQ01EX1BVICAgICAgICAgICAgICAgIEJJVCgyMSkKPj4gKyNkZWZp bmUgRU1NQzVfRkNfRFFfUEQgICAgICAgICAgICAgICAgQklUKDE2KQo+PiArI2RlZmluZSBFTU1D NV9GQ19EUV9QVSAgICAgICAgICAgICAgICBCSVQoMjApCj4+ICsKPj4gKyNkZWZpbmUgRU1NQ19Q SFlfUEFEX0NPTlRST0wxICAgICAgICAgICAgKEVNTUNfUEhZX1JFR19CQVNFICsgMHhDKQo+PiAr I2RlZmluZSBFTU1DNV8xX0ZDX1FTUF9QRCAgICAgICAgICAgIEJJVCg5KQo+PiArI2RlZmluZSBF TU1DNV8xX0ZDX1FTUF9QVSAgICAgICAgICAgIEJJVCgyNSkKPj4gKyNkZWZpbmUgRU1NQzVfMV9G Q19DTURfUEQgICAgICAgICAgICBCSVQoOCkKPj4gKyNkZWZpbmUgRU1NQzVfMV9GQ19DTURfUFUg ICAgICAgICAgICBCSVQoMjQpCj4+ICsjZGVmaW5lIEVNTUM1XzFfRkNfRFFfUEQgICAgICAgICAg ICAweEZGCj4+ICsjZGVmaW5lIEVNTUM1XzFfRkNfRFFfUFUgICAgICAgICAgICAoMHhGRiA8PCAx NikKPj4gKwo+PiArI2RlZmluZSBFTU1DX1BIWV9QQURfQ09OVFJPTDIgICAgICAgICAgICAoRU1N Q19QSFlfUkVHX0JBU0UgKyAweDEwKQo+PiArI2RlZmluZSBFTU1DXzVfMF9QSFlfUEFEX0NPTlRS T0wyICAgICAgICAoRU1NQ181XzBfUEhZX1JFR19CQVNFICsgMHhDKQo+PiArI2RlZmluZSBaTlJf TUFTSyAgICAgICAgICAgICAgICAweDFGCj4+ICsjZGVmaW5lIFpOUl9TSElGVCAgICAgICAgICAg ICAgICA4Cj4+ICsjZGVmaW5lIFpQUl9NQVNLICAgICAgICAgICAgICAgIDB4MUYKPj4gKy8qIFBl cmZlcnJlZCBaTlIgYW5kIFpQUiB2YWx1ZSB2YXJ5IGJldHdlZW4gZGlmZmVyZW50IGJvYXJkcy4K Pj4gKyAqIFRoZSBzcGVjaWZpYyBaTlIgYW5kIFpQUiB2YWx1ZSBzaG91bGQgYmUgZGVmaW5lZCBo ZXJlCj4+ICsgKiBhY2NvcmRpbmcgdG8gYm9hcmQgYWN0dWFsIHRpbWluZy4KPj4gKyAqLwo+PiAr I2RlZmluZSBaTlJfREVGX1ZBTFVFICAgICAgICAgICAgICAgIDB4Rgo+PiArI2RlZmluZSBaUFJf REVGX1ZBTFVFICAgICAgICAgICAgICAgIDB4Rgo+PiArCj4+ICsjZGVmaW5lIEVNTUNfUEhZX0RM TF9DT05UUk9MICAgICAgICAgICAgKEVNTUNfUEhZX1JFR19CQVNFICsgMHgxNCkKPj4gKyNkZWZp bmUgRU1NQ181XzBfUEhZX0RMTF9DT05UUk9MICAgICAgICAoRU1NQ181XzBfUEhZX1JFR19CQVNF ICsgMHgxMCkKPj4gKyNkZWZpbmUgRExMX0VOQUJMRSAgICAgICAgICAgICAgICBCSVQoMzEpCj4+ ICsjZGVmaW5lIERMTF9VUERBVEVfU1RST0JFXzVfMCAgICAgICAgICAgIEJJVCgzMCkKPj4gKyNk ZWZpbmUgRExMX1JFRkNMS19TRUwgICAgICAgICAgICAgICAgQklUKDMwKQo+PiArI2RlZmluZSBE TExfVVBEQVRFICAgICAgICAgICAgICAgIEJJVCgyMykKPj4gKyNkZWZpbmUgRExMX1BIU0VMMV9T SElGVCAgICAgICAgICAgIDI0Cj4+ICsjZGVmaW5lIERMTF9QSFNFTDBfU0hJRlQgICAgICAgICAg ICAxNgo+PiArI2RlZmluZSBETExfUEhBU0VfTUFTSyAgICAgICAgICAgICAgICAweDNGCj4+ICsj ZGVmaW5lIERMTF9QSEFTRV85MF9ERUdSRUUgICAgICAgICAgICAweDFGCj4+ICsjZGVmaW5lIERM TF9GQVNUX0xPQ0sgICAgICAgICAgICAgICAgQklUKDUpCj4+ICsjZGVmaW5lIERMTF9HQUlOMlgg ICAgICAgICAgICAgICAgQklUKDMpCj4+ICsjZGVmaW5lIERMTF9CWVBBU1NfRU4gICAgICAgICAg ICAgICAgQklUKDApCj4+ICsKPj4gKyNkZWZpbmUgRU1NQ181XzBfUEhZX0xPR0lDX1RJTUlOR19B REpVU1QgICAgKEVNTUNfNV8wX1BIWV9SRUdfQkFTRSArIDB4MTQpCj4+ICsjZGVmaW5lIEVNTUNf UEhZX0xPR0lDX1RJTUlOR19BREpVU1QgICAgICAgIChFTU1DX1BIWV9SRUdfQkFTRSArIDB4MTgp Cj4+ICsKPj4gK2VudW0gc2FtcGxfZml4X2RlbGF5X3BoYXNlIHsKPj4gKyAgICBQSEFTRV8wX0RF R1JFRSA9IDB4MCwKPj4gKyAgICBQSEFTRV85MF9ERUdSRUUgPSAweDEsCj4+ICsgICAgUEhBU0Vf MTgwX0RFR1JFRSA9IDB4MiwKPj4gKyAgICBQSEFTRV8yNzBfREVHUkVFID0gMHgzLAo+PiArfTsK Pj4gKwo+PiArI2RlZmluZSBTREhfUEhZX1NMT1RfRExMX0NUUkwgICAgICAgICAgICAoMHgwMTM4 KQo+PiArI2RlZmluZSBTREhfUEhZX0VOQUJMRV9ETEwgICAgICAgICAgICBCSVQoMSkKPj4gKyNk ZWZpbmUgU0RIX1BIWV9GQVNUX0xPQ0tfRU4gICAgICAgICAgICBCSVQoNSkKPj4gKwo+PiArI2Rl ZmluZSBTREhfUEhZX1NMT1RfRExMX1BIQVNFX1NFTCAgICAgICAgKDB4MDEzQykKPj4gKyNkZWZp bmUgU0RIX1BIWV9ETExfVVBEQVRFX1RVTklORyAgICAgICAgQklUKDE1KQo+PiArCj4+ICtlbnVt IHNvY19wYWRfY3RybF90eXBlIHsKPj4gKyAgICBTT0NfUEFEX1NELAo+PiArICAgIFNPQ19QQURf RklYRURfMV84ViwKPj4gK307Cj4+ICsKPj4gKy8qCj4+ICsgKiBMaXN0IG9mZnNldCBvZiBQSFkg cmVnaXN0ZXJzIGFuZCBzb21lIHNwZWNpYWwgcmVnaXN0ZXIgdmFsdWVzCj4+ICsgKiBpbiBlTU1D IFBIWSA1LjAgb3IgZU1NQyBQSFkgNS4xCj4+ICsgKi8KPj4gK3N0cnVjdCB4ZW5vbl9lbW1jX3Bo eV9yZWdzIHsKPj4gKyAgICAvKiBPZmZzZXQgb2YgVGltaW5nIEFkanVzdCByZWdpc3RlciAqLwo+ PiArICAgIHUxNiB0aW1pbmdfYWRqOwo+PiArICAgIC8qIE9mZnNldCBvZiBGdW5jIENvbnRyb2wg cmVnaXN0ZXIgKi8KPj4gKyAgICB1MTYgZnVuY19jdHJsOwo+PiArICAgIC8qIE9mZnNldCBvZiBQ YWQgQ29udHJvbCByZWdpc3RlciAqLwo+PiArICAgIHUxNiBwYWRfY3RybDsKPj4gKyAgICAvKiBP ZmZzZXQgb2YgUGFkIENvbnRyb2wgcmVnaXN0ZXIgKi8KPj4gKyAgICB1MTYgcGFkX2N0cmwyOwo+ PiArICAgIC8qIE9mZnNldCBvZiBETEwgQ29udHJvbCByZWdpc3RlciAqLwo+PiArICAgIHUxNiBk bGxfY3RybDsKPj4gKyAgICAvKiBPZmZzZXQgb2YgTG9naWMgVGltaW5nIEFkanVzdCByZWdpc3Rl ciAqLwo+PiArICAgIHUxNiBsb2dpY190aW1pbmdfYWRqOwo+PiArICAgIC8qIE1heCB2YWx1ZSBv ZiBlTU1DIEZpeGVkIFNhbXBsaW5nIERlbGF5ICovCj4+ICsgICAgdTMyIGRlbGF5X21hc2s7Cj4+ ICsgICAgLyogRExMIFVwZGF0ZSBFbmFibGUgYml0ICovCj4+ICsgICAgdTMyIGRsbF91cGRhdGU7 Cj4+ICt9Owo+PiArCj4+ICtzdHJ1Y3QgeGVub25fcGh5X29wcyB7Cj4+ICsgICAgdm9pZCAoKnN0 cm9iZV9kZWxheV9hZGopKHN0cnVjdCBzZGhjaV9ob3N0ICpob3N0LAo+PiArICAgICAgICAgICAg ICAgICBzdHJ1Y3QgbW1jX2NhcmQgKmNhcmQpOwo+PiArICAgIGludCAoKmZpeF9zYW1wbF9kZWxh eV9hZGopKHN0cnVjdCBzZGhjaV9ob3N0ICpob3N0LAo+PiArICAgICAgICAgICAgICAgICAgIHN0 cnVjdCBtbWNfY2FyZCAqY2FyZCk7Cj4+ICsgICAgdm9pZCAoKnBoeV9zZXQpKHN0cnVjdCBzZGhj aV9ob3N0ICpob3N0LCB1bnNpZ25lZCBjaGFyIHRpbWluZyk7Cj4+ICsgICAgdm9pZCAoKnNldF9z b2NfcGFkKShzdHJ1Y3Qgc2RoY2lfaG9zdCAqaG9zdCwKPj4gKyAgICAgICAgICAgICAgICB1bnNp Z25lZCBjaGFyIHNpZ25hbF92b2x0YWdlKTsKPj4gK307Cj4+ICsjZW5kaWYKPj4gZGlmZiAtLWdp dCBhL2RyaXZlcnMvbW1jL2hvc3Qvc2RoY2kteGVub24uYyBiL2RyaXZlcnMvbW1jL2hvc3Qvc2Ro Y2kteGVub24uYwo+PiBpbmRleCAwM2JhMTgzNDk0ZDMuLjRkN2Q4NzE1NDRmYyAxMDA2NDQKPj4g LS0tIGEvZHJpdmVycy9tbWMvaG9zdC9zZGhjaS14ZW5vbi5jCj4+ICsrKyBiL2RyaXZlcnMvbW1j L2hvc3Qvc2RoY2kteGVub24uYwo+PiBAQCAtMjI0LDYgKzIyNCw3IEBAIHN0YXRpYyB2b2lkIHhl bm9uX3NldF9pb3Moc3RydWN0IG1tY19ob3N0ICptbWMsIHN0cnVjdCBtbWNfaW9zICppb3MpCj4+ ICAgICAgc3Bpbl91bmxvY2tfaXJxcmVzdG9yZSgmaG9zdC0+bG9jaywgZmxhZ3MpOwo+Pgo+PiAg ICAgIHNkaGNpX3NldF9pb3MobW1jLCBpb3MpOwo+PiArICAgIHhlbm9uX3BoeV9hZGooaG9zdCwg aW9zKTsKPj4KPj4gICAgICBpZiAoaG9zdC0+Y2xvY2sgPiBERUZBVUxUX1NEQ0xLX0ZSRVEpIHsK Pj4gICAgICAgICAgc3Bpbl9sb2NrX2lycXNhdmUoJmhvc3QtPmxvY2ssIGZsYWdzKTsKPj4gQEAg LTMwOSw2ICszMTAsOCBAQCBzdGF0aWMgaW50IHhlbm9uX3N0YXJ0X3NpZ25hbF92b2x0YWdlX3N3 aXRjaChzdHJ1Y3QgbW1jX2hvc3QgKm1tYywKPj4gICAgICAgKi8KPj4gICAgICBlbmFibGVfeGVu b25faW50ZXJuYWxfY2xrKGhvc3QpOwo+Pgo+PiArICAgIHhlbm9uX3NvY19wYWRfY3RybChob3N0 LCBpb3MtPnNpZ25hbF92b2x0YWdlKTsKPj4gKwo+PiAgICAgIGlmIChwcml2LT5jYXJkX2NhbmRp ZGF0ZSkgewo+PiAgICAgICAgICBpZiAobW1jX2NhcmRfbW1jKHByaXYtPmNhcmRfY2FuZGlkYXRl KSkKPj4gICAgICAgICAgICAgIHJldHVybiB4ZW5vbl9lbW1jX3NpZ25hbF92b2x0YWdlX3N3aXRj aChtbWMsIGlvcyk7Cj4+IEBAIC00NTMsNiArNDU2LDcgQEAgc3RhdGljIGludCB4ZW5vbl9wcm9i ZV9kdChzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNlICpwZGV2KQo+PiAgICAgICAgICBzZGhjaV93cml0 ZWwoaG9zdCwgcmVnLCBTREhDX1NZU19FWFRfT1BfQ1RSTCk7Cj4+ICAgICAgfQo+Pgo+PiArICAg IGVyciA9IHhlbm9uX3BoeV9wYXJzZV9kdChucCwgaG9zdCk7Cj4+ICAgICAgcmV0dXJuIGVycjsK Pj4gIH0KPj4KPj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvbW1jL2hvc3Qvc2RoY2kteGVub24uaCBi L2RyaXZlcnMvbW1jL2hvc3Qvc2RoY2kteGVub24uaAo+PiBpbmRleCBjMjM3MDQ5M2ZiZTguLjA2 ZTUyNjFhNTYzYyAxMDA2NDQKPj4gLS0tIGEvZHJpdmVycy9tbWMvaG9zdC9zZGhjaS14ZW5vbi5o Cj4+ICsrKyBiL2RyaXZlcnMvbW1jL2hvc3Qvc2RoY2kteGVub24uaAo+PiBAQCAtMTUsNiArMTUs NyBAQAo+PiAgI2luY2x1ZGUgPGxpbnV4L21tYy9jYXJkLmg+Cj4+ICAjaW5jbHVkZSA8bGludXgv b2YuaD4KPj4gICNpbmNsdWRlICJzZGhjaS5oIgo+PiArI2luY2x1ZGUgInNkaGNpLXhlbm9uLXBo eS5oIgo+Pgo+PiAgLyogUmVnaXN0ZXIgT2Zmc2V0IG9mIFNEIEhvc3QgQ29udHJvbGxlciBTT0NQ IHNlbGYtZGVmaW5lZCByZWdpc3RlciAqLwo+PiAgI2RlZmluZSBTREhDX1NZU19DRkdfSU5GTyAg ICAgICAgICAgIDB4MDEwNAo+PiBAQCAtNzYsNiArNzcsNyBAQAo+PiAgI2RlZmluZSBNTUNfVElN SU5HX0ZBS0UgICAgICAgICAgICAgICAgMHhGRgo+Pgo+PiAgI2RlZmluZSBERUZBVUxUX1NEQ0xL X0ZSRVEgICAgICAgICAgICAoNDAwMDAwKQo+PiArI2RlZmluZSBMT1dFU1RfU0RDTEtfRlJFUSAg ICAgICAgICAgICgxMDAwMDApCj4+Cj4+ICAvKiBYZW5vbiBzcGVjaWZpYyBNb2RlIFNlbGVjdCB2 YWx1ZSAqLwo+PiAgI2RlZmluZSBYRU5PTl9TREhDSV9DVFJMX0hTMjAwICAgICAgICAgICAgMHg1 Cj4+IEBAIC05Nyw2ICs5OSwxNSBAQCBzdHJ1Y3Qgc2RoY2lfeGVub25fcHJpdiB7Cj4+ICAgICAg LyogU2xvdCBpZHggKi8KPj4gICAgICB1OCAgICAgICAgc2xvdF9pZHg7Cj4+Cj4+ICsgICAgaW50 ICAgICAgICBwaHlfdHlwZTsKPj4gKyAgICAvKgo+PiArICAgICAqIENvbnRhaW5zIGJvYXJkLXNw ZWNpZmljIFBIWSBwYXJhbWV0ZXJzCj4+ICsgICAgICogcGFzc2VkIGZyb20gZGV2aWNlIHRyZWUu Cj4+ICsgICAgICovCj4+ICsgICAgdm9pZCAgICAgICAgKnBoeV9wYXJhbXM7Cj4+ICsgICAgY29u c3Qgc3RydWN0IHhlbm9uX3BoeV9vcHMgKnBoeV9vcHM7Cj4+ICsgICAgc3RydWN0IHhlbm9uX2Vt bWNfcGh5X3JlZ3MgKmVtbWNfcGh5X3JlZ3M7Cj4+ICsKPj4gICAgICAvKgo+PiAgICAgICAqIFdo ZW4gaW5pdGlhbGl6aW5nIGNhcmQsIFhlbm9uIGhhcyB0byBkZXRlcm1pbmUgY2FyZCB0eXBlIGFu ZAo+PiAgICAgICAqIGFkanVzdCBTYW1wbGluZyBGaXhlZCBkZWxheS4KPj4gQEAgLTEzMSw0ICsx NDIsMTAgQEAgc3RhdGljIGlubGluZSBpbnQgZW5hYmxlX3hlbm9uX2ludGVybmFsX2NsayhzdHJ1 Y3Qgc2RoY2lfaG9zdCAqaG9zdCkKPj4KPj4gICAgICByZXR1cm4gMDsKPj4gIH0KPj4gKwo+PiAr aW50IHhlbm9uX3BoeV9hZGooc3RydWN0IHNkaGNpX2hvc3QgKmhvc3QsIHN0cnVjdCBtbWNfaW9z ICppb3MpOwo+PiAraW50IHhlbm9uX3BoeV9wYXJzZV9kdChzdHJ1Y3QgZGV2aWNlX25vZGUgKm5w LAo+PiArICAgICAgICAgICAgICAgc3RydWN0IHNkaGNpX2hvc3QgKmhvc3QpOwo+PiArdm9pZCB4 ZW5vbl9zb2NfcGFkX2N0cmwoc3RydWN0IHNkaGNpX2hvc3QgKmhvc3QsCj4+ICsgICAgICAgICAg ICB1bnNpZ25lZCBjaGFyIHNpZ25hbF92b2x0YWdlKTsKPj4gICNlbmRpZgo+Pgo+IAo+IAoKX19f X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18KbGludXgtYXJtLWtl cm5lbCBtYWlsaW5nIGxpc3QKbGludXgtYXJtLWtlcm5lbEBsaXN0cy5pbmZyYWRlYWQub3JnCmh0 dHA6Ly9saXN0cy5pbmZyYWRlYWQub3JnL21haWxtYW4vbGlzdGluZm8vbGludXgtYXJtLWtlcm5l bAo= From mboxrd@z Thu Jan 1 00:00:00 1970 From: huziji@marvell.com (Ziji Hu) Date: Sat, 8 Oct 2016 17:28:47 +0800 Subject: [PATCH 7/10] mmc: sdhci-xenon: Add support to PHYs of Marvell Xenon SDHC In-Reply-To: <25146173-d98b-f346-b333-4d7466960496@rock-chips.com> References: <25146173-d98b-f346-b333-4d7466960496@rock-chips.com> Message-ID: To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org Hi Shawn, On 2016/10/8 10:44, Shawn Lin wrote: > ? 2016/10/7 23:22, Gregory CLEMENT ??: >> From: Ziji Hu >> >> Marvell Xenon eMMC/SD/SDIO Host Controller contains PHY. >> Three types of PHYs are supported. >> >> Add support to multiple types of PHYs init and configuration. >> Add register definitions of PHYs. >> >> Signed-off-by: Hu Ziji >> Reviewed-by: Gregory CLEMENT >> Signed-off-by: Gregory CLEMENT >> --- >> MAINTAINERS | 1 +- >> drivers/mmc/host/Makefile | 2 +- >> drivers/mmc/host/sdhci-xenon-phy.c | 1141 +++++++++++++++++++++++++++++- >> drivers/mmc/host/sdhci-xenon-phy.h | 157 ++++- >> drivers/mmc/host/sdhci-xenon.c | 4 +- >> drivers/mmc/host/sdhci-xenon.h | 17 +- >> 6 files changed, 1321 insertions(+), 1 deletion(-) >> create mode 100644 drivers/mmc/host/sdhci-xenon-phy.c >> create mode 100644 drivers/mmc/host/sdhci-xenon-phy.h >> >> diff --git a/MAINTAINERS b/MAINTAINERS >> index 859420e5dfd3..b5673c2ee5f2 100644 >> --- a/MAINTAINERS >> +++ b/MAINTAINERS >> @@ -7583,6 +7583,7 @@ M: Ziji Hu >> L: linux-mmc at vger.kernel.org >> S: Supported >> F: drivers/mmc/host/sdhci-xenon.* >> +F: drivers/mmc/host/sdhci-xenon-phy.* > > drivers/mmc/host/sdhci-xenon* shoube enough > >> F: Documentation/devicetree/bindings/mmc/marvell,sdhci-xenon.txt >> >> MATROX FRAMEBUFFER DRIVER >> diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile >> index 75eaf743486c..4f2854556ff7 100644 >> --- a/drivers/mmc/host/Makefile >> +++ b/drivers/mmc/host/Makefile >> @@ -82,4 +82,4 @@ ifeq ($(CONFIG_CB710_DEBUG),y) >> endif >> >> obj-$(CONFIG_MMC_SDHCI_XENON) += sdhci-xenon-driver.o >> -sdhci-xenon-driver-y += sdhci-xenon.o >> +sdhci-xenon-driver-y += sdhci-xenon.o sdhci-xenon-phy.o >> diff --git a/drivers/mmc/host/sdhci-xenon-phy.c b/drivers/mmc/host/sdhci-xenon-phy.c >> new file mode 100644 >> index 000000000000..4eb8fea1bec9 >> --- /dev/null >> +++ b/drivers/mmc/host/sdhci-xenon-phy.c > > Well, it's legit to use phy API and move your phy > operations to PHY subsystem. :) > Actually we tried to put the PHY code into Linux PHY framework. But it cannot fit in Linux common PHY framework. Our Xenon SDHC PHY register is a part of Xenon SDHC register set. Besides, during MMC initialization, MMC sequence has to call several PHY functions to complete timing setting. In those PHY setting functions, they have to access SDHC register and know current MMC setting, such as bus width, clock frequency and speed mode. As a result, we have to implement PHY under MMC directory. Thank you. Best regards, Hu Ziji >> @@ -0,0 +1,1141 @@ >> +/* >> + * PHY support for Xenon SDHC >> + * >> + * Copyright (C) 2016 Marvell, All Rights Reserved. >> + * >> + * Author: Hu Ziji >> + * Date: 2016-8-24 >> + * >> + * This program is free software; you can redistribute it and/or >> + * modify it under the terms of the GNU General Public License as >> + * published by the Free Software Foundation version 2. >> + */ >> + >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +#include "sdhci.h" >> +#include "sdhci-pltfm.h" >> +#include "sdhci-xenon.h" >> + >> +static const char * const phy_types[] = { >> + "sdh phy", >> + "emmc 5.0 phy", >> + "emmc 5.1 phy" >> +}; >> + >> +enum phy_type_enum { >> + SDH_PHY, >> + EMMC_5_0_PHY, >> + EMMC_5_1_PHY, >> + NR_PHY_TYPES >> +}; >> + >> +struct soc_pad_ctrl_table { >> + const char *soc; >> + void (*set_soc_pad)(struct sdhci_host *host, >> + unsigned char signal_voltage); >> +}; >> + >> +struct soc_pad_ctrl { >> + /* Register address of SOC PHY PAD ctrl */ >> + void __iomem *reg; >> + /* SOC PHY PAD ctrl type */ >> + enum soc_pad_ctrl_type pad_type; >> + /* SOC specific operation to set SOC PHY PAD */ >> + void (*set_soc_pad)(struct sdhci_host *host, >> + unsigned char signal_voltage); >> +}; >> + >> +static struct xenon_emmc_phy_regs xenon_emmc_5_0_phy_regs = { >> + .timing_adj = EMMC_5_0_PHY_TIMING_ADJUST, >> + .func_ctrl = EMMC_5_0_PHY_FUNC_CONTROL, >> + .pad_ctrl = EMMC_5_0_PHY_PAD_CONTROL, >> + .pad_ctrl2 = EMMC_5_0_PHY_PAD_CONTROL2, >> + .dll_ctrl = EMMC_5_0_PHY_DLL_CONTROL, >> + .logic_timing_adj = EMMC_5_0_PHY_LOGIC_TIMING_ADJUST, >> + .delay_mask = EMMC_5_0_PHY_FIXED_DELAY_MASK, >> + .dll_update = DLL_UPDATE_STROBE_5_0, >> +}; >> + >> +static struct xenon_emmc_phy_regs xenon_emmc_5_1_phy_regs = { >> + .timing_adj = EMMC_PHY_TIMING_ADJUST, >> + .func_ctrl = EMMC_PHY_FUNC_CONTROL, >> + .pad_ctrl = EMMC_PHY_PAD_CONTROL, >> + .pad_ctrl2 = EMMC_PHY_PAD_CONTROL2, >> + .dll_ctrl = EMMC_PHY_DLL_CONTROL, >> + .logic_timing_adj = EMMC_PHY_LOGIC_TIMING_ADJUST, >> + .delay_mask = EMMC_PHY_FIXED_DELAY_MASK, >> + .dll_update = DLL_UPDATE, >> +}; >> + >> +static int xenon_delay_adj_test(struct mmc_card *card); >> + >> +/* >> + * eMMC PHY configuration and operations >> + */ >> +struct emmc_phy_params { >> + bool slow_mode; >> + >> + u8 znr; >> + u8 zpr; >> + >> + /* Nr of consecutive Sampling Points of a Valid Sampling Window */ >> + u8 nr_tun_times; >> + /* Divider for calculating Tuning Step */ >> + u8 tun_step_divider; >> + >> + struct soc_pad_ctrl pad_ctrl; >> +}; >> + >> +static void xenon_emmc_phy_strobe_delay_adj(struct sdhci_host *host, >> + struct mmc_card *card); >> +static int xenon_emmc_phy_fix_sampl_delay_adj(struct sdhci_host *host, >> + struct mmc_card *card); >> +static void xenon_emmc_phy_set(struct sdhci_host *host, >> + unsigned char timing); >> +static void xenon_emmc_set_soc_pad(struct sdhci_host *host, >> + unsigned char signal_voltage); >> + >> +static const struct xenon_phy_ops emmc_phy_ops = { >> + .strobe_delay_adj = xenon_emmc_phy_strobe_delay_adj, >> + .fix_sampl_delay_adj = xenon_emmc_phy_fix_sampl_delay_adj, >> + .phy_set = xenon_emmc_phy_set, >> + .set_soc_pad = xenon_emmc_set_soc_pad, >> +}; >> + >> +static int alloc_emmc_phy(struct sdhci_xenon_priv *priv) >> +{ >> + struct emmc_phy_params *params; >> + >> + params = kzalloc(sizeof(*params), GFP_KERNEL); >> + if (!params) >> + return -ENOMEM; >> + >> + priv->phy_params = params; >> + priv->phy_ops = &emmc_phy_ops; >> + if (priv->phy_type == EMMC_5_0_PHY) >> + priv->emmc_phy_regs = &xenon_emmc_5_0_phy_regs; >> + else >> + priv->emmc_phy_regs = &xenon_emmc_5_1_phy_regs; >> + >> + return 0; >> +} >> + >> +static int xenon_emmc_phy_init(struct sdhci_host *host) >> +{ >> + u32 reg; >> + u32 wait, clock; >> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >> + struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); >> + struct xenon_emmc_phy_regs *phy_regs = priv->emmc_phy_regs; >> + >> + reg = sdhci_readl(host, phy_regs->timing_adj); >> + reg |= PHY_INITIALIZAION; >> + sdhci_writel(host, reg, phy_regs->timing_adj); >> + >> + /* Add duration of FC_SYNC_RST */ >> + wait = ((reg >> FC_SYNC_RST_DURATION_SHIFT) & >> + FC_SYNC_RST_DURATION_MASK); >> + /* Add interval between FC_SYNC_EN and FC_SYNC_RST */ >> + wait += ((reg >> FC_SYNC_RST_EN_DURATION_SHIFT) & >> + FC_SYNC_RST_EN_DURATION_MASK); >> + /* Add duration of asserting FC_SYNC_EN */ >> + wait += ((reg >> FC_SYNC_EN_DURATION_SHIFT) & >> + FC_SYNC_EN_DURATION_MASK); >> + /* Add duration of waiting for PHY */ >> + wait += ((reg >> WAIT_CYCLE_BEFORE_USING_SHIFT) & >> + WAIT_CYCLE_BEFORE_USING_MASK); >> + /* 4 addtional bus clock and 4 AXI bus clock are required */ >> + wait += 8; >> + wait <<= 20; >> + >> + clock = host->clock; >> + if (!clock) >> + /* Use the possibly slowest bus frequency value */ >> + clock = LOWEST_SDCLK_FREQ; >> + /* get the wait time */ >> + wait /= clock; >> + wait++; >> + /* wait for host eMMC PHY init completes */ >> + udelay(wait); >> + >> + reg = sdhci_readl(host, phy_regs->timing_adj); >> + reg &= PHY_INITIALIZAION; >> + if (reg) { >> + dev_err(mmc_dev(host->mmc), "eMMC PHY init cannot complete after %d us\n", >> + wait); >> + return -ETIMEDOUT; >> + } >> + >> + return 0; >> +} >> + >> +#define ARMADA_3700_SOC_PAD_1_8V 0x1 >> +#define ARMADA_3700_SOC_PAD_3_3V 0x0 >> + >> +static void armada_3700_soc_pad_voltage_set(struct sdhci_host *host, >> + unsigned char signal_voltage) >> +{ >> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >> + struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); >> + struct emmc_phy_params *params = priv->phy_params; >> + >> + if (params->pad_ctrl.pad_type == SOC_PAD_FIXED_1_8V) { >> + writel(ARMADA_3700_SOC_PAD_1_8V, params->pad_ctrl.reg); >> + } else if (params->pad_ctrl.pad_type == SOC_PAD_SD) { >> + if (signal_voltage == MMC_SIGNAL_VOLTAGE_180) >> + writel(ARMADA_3700_SOC_PAD_1_8V, params->pad_ctrl.reg); >> + else if (signal_voltage == MMC_SIGNAL_VOLTAGE_330) >> + writel(ARMADA_3700_SOC_PAD_3_3V, params->pad_ctrl.reg); >> + } >> +} >> + >> +static void xenon_emmc_set_soc_pad(struct sdhci_host *host, >> + unsigned char signal_voltage) >> +{ >> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >> + struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); >> + struct emmc_phy_params *params = priv->phy_params; >> + >> + if (!params->pad_ctrl.reg) >> + return; >> + >> + if (params->pad_ctrl.set_soc_pad) >> + params->pad_ctrl.set_soc_pad(host, signal_voltage); >> +} >> + >> +static int emmc_phy_set_fix_sampl_delay(struct sdhci_host *host, >> + unsigned int delay, >> + bool invert, >> + bool delay_90_degree) >> +{ >> + u32 reg; >> + unsigned long flags; >> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >> + struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); >> + struct xenon_emmc_phy_regs *phy_regs = priv->emmc_phy_regs; >> + int ret = 0; >> + >> + spin_lock_irqsave(&host->lock, flags); >> + >> + /* Setup Sampling fix delay */ >> + reg = sdhci_readl(host, SDHC_SLOT_OP_STATUS_CTRL); >> + reg &= ~phy_regs->delay_mask; >> + reg |= delay & phy_regs->delay_mask; >> + sdhci_writel(host, reg, SDHC_SLOT_OP_STATUS_CTRL); >> + >> + if (priv->phy_type == EMMC_5_0_PHY) { >> + /* set 90 degree phase if necessary */ >> + reg &= ~DELAY_90_DEGREE_MASK_EMMC5; >> + reg |= (delay_90_degree << DELAY_90_DEGREE_SHIFT_EMMC5); >> + sdhci_writel(host, reg, SDHC_SLOT_OP_STATUS_CTRL); >> + } >> + >> + /* Disable SDCLK */ >> + reg = sdhci_readl(host, SDHCI_CLOCK_CONTROL); >> + reg &= ~(SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_INT_EN); >> + sdhci_writel(host, reg, SDHCI_CLOCK_CONTROL); >> + >> + udelay(200); >> + >> + if (priv->phy_type == EMMC_5_1_PHY) { >> + /* set 90 degree phase if necessary */ >> + reg = sdhci_readl(host, EMMC_PHY_FUNC_CONTROL); >> + reg &= ~ASYNC_DDRMODE_MASK; >> + reg |= (delay_90_degree << ASYNC_DDRMODE_SHIFT); >> + sdhci_writel(host, reg, EMMC_PHY_FUNC_CONTROL); >> + } >> + >> + /* Setup Inversion of Sampling edge */ >> + reg = sdhci_readl(host, phy_regs->timing_adj); >> + reg &= ~SAMPL_INV_QSP_PHASE_SELECT; >> + reg |= (invert << SAMPL_INV_QSP_PHASE_SELECT_SHIFT); >> + sdhci_writel(host, reg, phy_regs->timing_adj); >> + >> + /* Enable SD internal clock */ >> + ret = enable_xenon_internal_clk(host); >> + if (ret) >> + goto out; >> + >> + /* Enable SDCLK */ >> + reg = sdhci_readl(host, SDHCI_CLOCK_CONTROL); >> + reg |= SDHCI_CLOCK_CARD_EN; >> + sdhci_writel(host, reg, SDHCI_CLOCK_CONTROL); >> + >> + udelay(200); >> + >> + /* >> + * Has to re-initialize eMMC PHY here to active PHY >> + * because later get status cmd will be issued. >> + */ >> + ret = xenon_emmc_phy_init(host); >> + >> +out: >> + spin_unlock_irqrestore(&host->lock, flags); >> + return ret; >> +} >> + >> +static int emmc_phy_do_fix_sampl_delay(struct sdhci_host *host, >> + struct mmc_card *card, >> + unsigned int delay, >> + bool invert, bool quarter) >> +{ >> + int ret; >> + >> + emmc_phy_set_fix_sampl_delay(host, delay, invert, quarter); >> + >> + ret = xenon_delay_adj_test(card); >> + if (ret) { >> + dev_dbg(mmc_dev(host->mmc), >> + "fail when sampling fix delay = %d, phase = %d degree\n", >> + delay, invert * 180 + quarter * 90); >> + return -1; >> + } >> + return 0; >> +} >> + >> +static int xenon_emmc_phy_fix_sampl_delay_adj(struct sdhci_host *host, >> + struct mmc_card *card) >> +{ >> + enum sampl_fix_delay_phase phase; >> + int idx, nr_pair; >> + int ret; >> + unsigned int delay; >> + unsigned int min_delay, max_delay; >> + bool invert, quarter; >> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >> + struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); >> + struct xenon_emmc_phy_regs *phy_regs = priv->emmc_phy_regs; >> + u32 coarse_step, fine_step; >> + const enum sampl_fix_delay_phase delay_edge[] = { >> + PHASE_0_DEGREE, >> + PHASE_180_DEGREE, >> + PHASE_90_DEGREE, >> + PHASE_270_DEGREE >> + }; >> + >> + coarse_step = phy_regs->delay_mask >> 1; >> + fine_step = coarse_step >> 2; >> + >> + nr_pair = ARRAY_SIZE(delay_edge); >> + >> + for (idx = 0; idx < nr_pair; idx++) { >> + phase = delay_edge[idx]; >> + invert = (phase & 0x2) ? true : false; >> + quarter = (phase & 0x1) ? true : false; >> + >> + /* increase delay value to get fix delay */ >> + for (min_delay = 0; >> + min_delay <= phy_regs->delay_mask; >> + min_delay += coarse_step) { >> + ret = emmc_phy_do_fix_sampl_delay(host, card, min_delay, >> + invert, quarter); >> + if (!ret) >> + break; >> + } >> + >> + if (ret) { >> + dev_dbg(mmc_dev(host->mmc), >> + "Fail to set Sampling Fixed Delay with phase = %d degree\n", >> + phase * 90); >> + continue; >> + } >> + >> + for (max_delay = min_delay + fine_step; >> + max_delay < phy_regs->delay_mask; >> + max_delay += fine_step) { >> + ret = emmc_phy_do_fix_sampl_delay(host, card, max_delay, >> + invert, quarter); >> + if (ret) { >> + max_delay -= fine_step; >> + break; >> + } >> + } >> + >> + if (!ret) { >> + ret = emmc_phy_do_fix_sampl_delay(host, card, >> + phy_regs->delay_mask, >> + invert, quarter); >> + if (!ret) >> + max_delay = phy_regs->delay_mask; >> + } >> + >> + /* >> + * Sampling Fixed Delay line window should be large enough, >> + * thus the sampling point (the middle of the window) >> + * can work when environment varies. >> + * However, there is no clear conclusion how large the window >> + * should be. >> + */ >> + if ((max_delay - min_delay) <= >> + EMMC_PHY_FIXED_DELAY_WINDOW_MIN) { >> + dev_info(mmc_dev(host->mmc), >> + "The window size %d with phase = %d degree is too small\n", >> + max_delay - min_delay, phase * 90); >> + continue; >> + } >> + >> + delay = (min_delay + max_delay) / 2; >> + emmc_phy_set_fix_sampl_delay(host, delay, invert, quarter); >> + dev_dbg(mmc_dev(host->mmc), >> + "sampling fix delay = %d with phase = %d degree\n", >> + delay, phase * 90); >> + return 0; >> + } >> + >> + return -EIO; >> +} >> + >> +static int xenon_emmc_phy_enable_dll(struct sdhci_host *host) >> +{ >> + u32 reg; >> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >> + struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); >> + struct xenon_emmc_phy_regs *phy_regs = priv->emmc_phy_regs; >> + u8 timeout; >> + >> + if (WARN_ON(host->clock <= MMC_HIGH_52_MAX_DTR)) >> + return -EINVAL; >> + >> + reg = sdhci_readl(host, phy_regs->dll_ctrl); >> + if (reg & DLL_ENABLE) >> + return 0; >> + >> + /* Enable DLL */ >> + reg = sdhci_readl(host, phy_regs->dll_ctrl); >> + reg |= (DLL_ENABLE | DLL_FAST_LOCK); >> + >> + /* >> + * Set Phase as 90 degree, which is most common value. >> + * Might set another value if necessary. >> + * The granularity is 1 degree. >> + */ >> + reg &= ~((DLL_PHASE_MASK << DLL_PHSEL0_SHIFT) | >> + (DLL_PHASE_MASK << DLL_PHSEL1_SHIFT)); >> + reg |= ((DLL_PHASE_90_DEGREE << DLL_PHSEL0_SHIFT) | >> + (DLL_PHASE_90_DEGREE << DLL_PHSEL1_SHIFT)); >> + >> + reg &= ~DLL_BYPASS_EN; >> + reg |= phy_regs->dll_update; >> + if (priv->phy_type == EMMC_5_1_PHY) >> + reg &= ~DLL_REFCLK_SEL; >> + sdhci_writel(host, reg, phy_regs->dll_ctrl); >> + >> + /* Wait max 32 ms */ >> + timeout = 32; >> + while (!(sdhci_readw(host, SDHC_SLOT_EXT_PRESENT_STATE) & LOCK_STATE)) { >> + if (!timeout) { >> + dev_err(mmc_dev(host->mmc), "Wait for DLL Lock time-out\n"); >> + return -ETIMEDOUT; >> + } >> + timeout--; >> + mdelay(1); >> + } >> + return 0; >> +} >> + >> +static int __emmc_phy_config_tuning(struct sdhci_host *host) >> +{ >> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >> + struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); >> + struct emmc_phy_params *params = priv->phy_params; >> + u32 reg, tuning_step; >> + int ret; >> + unsigned long flags; >> + >> + if (WARN_ON(host->clock <= MMC_HIGH_52_MAX_DTR)) >> + return -EINVAL; >> + >> + spin_lock_irqsave(&host->lock, flags); >> + >> + ret = xenon_emmc_phy_enable_dll(host); >> + if (ret) { >> + spin_unlock_irqrestore(&host->lock, flags); >> + return ret; >> + } >> + >> + reg = sdhci_readl(host, SDHC_SLOT_DLL_CUR_DLY_VAL); >> + tuning_step = reg / params->tun_step_divider; >> + if (unlikely(tuning_step > TUNING_STEP_MASK)) { >> + dev_warn(mmc_dev(host->mmc), >> + "HS200 TUNING_STEP %d is larger than MAX value\n", >> + tuning_step); >> + tuning_step = TUNING_STEP_MASK; >> + } >> + >> + reg = sdhci_readl(host, SDHC_SLOT_OP_STATUS_CTRL); >> + reg &= ~(TUN_CONSECUTIVE_TIMES_MASK << TUN_CONSECUTIVE_TIMES_SHIFT); >> + reg |= (params->nr_tun_times << TUN_CONSECUTIVE_TIMES_SHIFT); >> + reg &= ~(TUNING_STEP_MASK << TUNING_STEP_SHIFT); >> + reg |= (tuning_step << TUNING_STEP_SHIFT); >> + sdhci_writel(host, reg, SDHC_SLOT_OP_STATUS_CTRL); >> + >> + spin_unlock_irqrestore(&host->lock, flags); >> + return 0; >> +} >> + >> +static int xenon_emmc_phy_config_tuning(struct sdhci_host *host) >> +{ >> + return __emmc_phy_config_tuning(host); >> +} >> + >> +static void xenon_emmc_phy_strobe_delay_adj(struct sdhci_host *host, >> + struct mmc_card *card) >> +{ >> + u32 reg; >> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >> + struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); >> + unsigned long flags; >> + >> + if (host->clock <= MMC_HIGH_52_MAX_DTR) >> + return; >> + >> + dev_dbg(mmc_dev(host->mmc), "starts HS400 strobe delay adjustment\n"); >> + >> + spin_lock_irqsave(&host->lock, flags); >> + >> + xenon_emmc_phy_enable_dll(host); >> + >> + /* Enable SDHC Data Strobe */ >> + reg = sdhci_readl(host, SDHC_SLOT_EMMC_CTRL); >> + reg |= ENABLE_DATA_STROBE; >> + sdhci_writel(host, reg, SDHC_SLOT_EMMC_CTRL); >> + >> + /* Set Data Strobe Pull down */ >> + if (priv->phy_type == EMMC_5_0_PHY) { >> + reg = sdhci_readl(host, EMMC_5_0_PHY_PAD_CONTROL); >> + reg |= EMMC5_FC_QSP_PD; >> + reg &= ~EMMC5_FC_QSP_PU; >> + sdhci_writel(host, reg, EMMC_5_0_PHY_PAD_CONTROL); >> + } else { >> + reg = sdhci_readl(host, EMMC_PHY_PAD_CONTROL1); >> + reg |= EMMC5_1_FC_QSP_PD; >> + reg &= ~EMMC5_1_FC_QSP_PU; >> + sdhci_writel(host, reg, EMMC_PHY_PAD_CONTROL1); >> + } >> + spin_unlock_irqrestore(&host->lock, flags); >> +} >> + >> +#define LOGIC_TIMING_VALUE 0x00AA8977 >> + >> +static void xenon_emmc_phy_set(struct sdhci_host *host, >> + unsigned char timing) >> +{ >> + u32 reg; >> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >> + struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); >> + struct emmc_phy_params *params = priv->phy_params; >> + struct xenon_emmc_phy_regs *phy_regs = priv->emmc_phy_regs; >> + struct mmc_card *card = priv->card_candidate; >> + unsigned long flags; >> + >> + dev_dbg(mmc_dev(host->mmc), "eMMC PHY setting starts\n"); >> + >> + spin_lock_irqsave(&host->lock, flags); >> + >> + /* Setup pad, set bit[28] and bits[26:24] */ >> + reg = sdhci_readl(host, phy_regs->pad_ctrl); >> + reg |= (FC_DQ_RECEN | FC_CMD_RECEN | FC_QSP_RECEN | OEN_QSN); >> + /* >> + * All FC_XX_RECEIVCE should be set as CMOS Type >> + */ >> + reg |= FC_ALL_CMOS_RECEIVER; >> + sdhci_writel(host, reg, phy_regs->pad_ctrl); >> + >> + /* Set CMD and DQ Pull Up */ >> + if (priv->phy_type == EMMC_5_0_PHY) { >> + reg = sdhci_readl(host, EMMC_5_0_PHY_PAD_CONTROL); >> + reg |= (EMMC5_FC_CMD_PU | EMMC5_FC_DQ_PU); >> + reg &= ~(EMMC5_FC_CMD_PD | EMMC5_FC_DQ_PD); >> + sdhci_writel(host, reg, EMMC_5_0_PHY_PAD_CONTROL); >> + } else { >> + reg = sdhci_readl(host, EMMC_PHY_PAD_CONTROL1); >> + reg |= (EMMC5_1_FC_CMD_PU | EMMC5_1_FC_DQ_PU); >> + reg &= ~(EMMC5_1_FC_CMD_PD | EMMC5_1_FC_DQ_PD); >> + sdhci_writel(host, reg, EMMC_PHY_PAD_CONTROL1); >> + } >> + >> + if ((timing == MMC_TIMING_LEGACY) || !card) >> + goto phy_init; >> + >> + /* >> + * FIXME: should depends on the specific board timing. >> + */ >> + if ((timing == MMC_TIMING_MMC_HS400) || >> + (timing == MMC_TIMING_MMC_HS200) || >> + (timing == MMC_TIMING_UHS_SDR50) || >> + (timing == MMC_TIMING_UHS_SDR104) || >> + (timing == MMC_TIMING_UHS_DDR50) || >> + (timing == MMC_TIMING_UHS_SDR25) || >> + (timing == MMC_TIMING_MMC_DDR52)) { >> + reg = sdhci_readl(host, phy_regs->timing_adj); >> + reg &= ~OUTPUT_QSN_PHASE_SELECT; >> + sdhci_writel(host, reg, phy_regs->timing_adj); >> + } >> + >> + /* >> + * If SDIO card, set SDIO Mode >> + * Otherwise, clear SDIO Mode and Slow Mode >> + */ >> + if (mmc_card_sdio(card)) { >> + reg = sdhci_readl(host, phy_regs->timing_adj); >> + reg |= TIMING_ADJUST_SDIO_MODE; >> + >> + if ((timing == MMC_TIMING_UHS_SDR25) || >> + (timing == MMC_TIMING_UHS_SDR12) || >> + (timing == MMC_TIMING_SD_HS) || >> + (timing == MMC_TIMING_LEGACY)) >> + reg |= TIMING_ADJUST_SLOW_MODE; >> + >> + sdhci_writel(host, reg, phy_regs->timing_adj); >> + } else { >> + reg = sdhci_readl(host, phy_regs->timing_adj); >> + reg &= ~(TIMING_ADJUST_SDIO_MODE | TIMING_ADJUST_SLOW_MODE); >> + sdhci_writel(host, reg, phy_regs->timing_adj); >> + } >> + >> + if (((timing == MMC_TIMING_UHS_SDR50) || >> + (timing == MMC_TIMING_UHS_SDR25) || >> + (timing == MMC_TIMING_UHS_SDR12) || >> + (timing == MMC_TIMING_SD_HS) || >> + (timing == MMC_TIMING_MMC_HS) || >> + (timing == MMC_TIMING_LEGACY)) && params->slow_mode) { >> + reg = sdhci_readl(host, phy_regs->timing_adj); >> + reg |= TIMING_ADJUST_SLOW_MODE; >> + sdhci_writel(host, reg, phy_regs->timing_adj); >> + } >> + >> + /* >> + * Set preferred ZNR and ZPR value >> + * The ZNR and ZPR value vary between different boards. >> + * Define them both in sdhci-xenon-emmc-phy.h. >> + */ >> + reg = sdhci_readl(host, phy_regs->pad_ctrl2); >> + reg &= ~((ZNR_MASK << ZNR_SHIFT) | ZPR_MASK); >> + reg |= ((params->znr << ZNR_SHIFT) | params->zpr); >> + sdhci_writel(host, reg, phy_regs->pad_ctrl2); >> + >> + /* >> + * When setting EMMC_PHY_FUNC_CONTROL register, >> + * SD clock should be disabled >> + */ >> + reg = sdhci_readl(host, SDHCI_CLOCK_CONTROL); >> + reg &= ~SDHCI_CLOCK_CARD_EN; >> + sdhci_writew(host, reg, SDHCI_CLOCK_CONTROL); >> + >> + if ((timing == MMC_TIMING_UHS_DDR50) || >> + (timing == MMC_TIMING_MMC_HS400) || >> + (timing == MMC_TIMING_MMC_DDR52)) { >> + reg = sdhci_readl(host, phy_regs->func_ctrl); >> + reg |= (DQ_DDR_MODE_MASK << DQ_DDR_MODE_SHIFT) | CMD_DDR_MODE; >> + sdhci_writel(host, reg, phy_regs->func_ctrl); >> + } >> + >> + if (timing == MMC_TIMING_MMC_HS400) { >> + reg = sdhci_readl(host, phy_regs->func_ctrl); >> + reg &= ~DQ_ASYNC_MODE; >> + sdhci_writel(host, reg, phy_regs->func_ctrl); >> + } >> + >> + /* Enable bus clock */ >> + reg = sdhci_readl(host, SDHCI_CLOCK_CONTROL); >> + reg |= SDHCI_CLOCK_CARD_EN; >> + sdhci_writew(host, reg, SDHCI_CLOCK_CONTROL); >> + >> + if (timing == MMC_TIMING_MMC_HS400) >> + /* Hardware team recommend a value for HS400 */ >> + sdhci_writel(host, LOGIC_TIMING_VALUE, >> + phy_regs->logic_timing_adj); >> + >> +phy_init: >> + xenon_emmc_phy_init(host); >> + >> + spin_unlock_irqrestore(&host->lock, flags); >> + >> + dev_dbg(mmc_dev(host->mmc), "eMMC PHY setting completes\n"); >> +} >> + >> +static int get_dt_pad_ctrl_data(struct sdhci_host *host, >> + struct device_node *np, >> + struct emmc_phy_params *params) >> +{ >> + int ret = 0; >> + const char *name; >> + struct resource iomem; >> + >> + if (of_device_is_compatible(np, "marvell,armada-3700-sdhci")) >> + params->pad_ctrl.set_soc_pad = armada_3700_soc_pad_voltage_set; >> + else >> + return 0; >> + >> + if (of_address_to_resource(np, 1, &iomem)) { >> + dev_err(mmc_dev(host->mmc), "Unable to find SOC PAD ctrl register address for %s\n", >> + np->name); >> + return -EINVAL; >> + } >> + >> + params->pad_ctrl.reg = devm_ioremap_resource(mmc_dev(host->mmc), >> + &iomem); >> + if (IS_ERR(params->pad_ctrl.reg)) { >> + dev_err(mmc_dev(host->mmc), "Unable to get SOC PHY PAD ctrl regiser for %s\n", >> + np->name); >> + return PTR_ERR(params->pad_ctrl.reg); >> + } >> + >> + ret = of_property_read_string(np, "xenon,pad-type", &name); >> + if (ret) { >> + dev_err(mmc_dev(host->mmc), "Unable to determine SOC PHY PAD ctrl type\n"); >> + return ret; >> + } >> + if (!strcmp(name, "sd")) { >> + params->pad_ctrl.pad_type = SOC_PAD_SD; >> + } else if (!strcmp(name, "fixed-1-8v")) { >> + params->pad_ctrl.pad_type = SOC_PAD_FIXED_1_8V; >> + } else { >> + dev_err(mmc_dev(host->mmc), "Unsupported SOC PHY PAD ctrl type %s\n", >> + name); >> + return -EINVAL; >> + } >> + >> + return ret; >> +} >> + >> +static int emmc_phy_parse_param_dt(struct sdhci_host *host, >> + struct device_node *np, >> + struct emmc_phy_params *params) >> +{ >> + u32 value; >> + >> + if (of_property_read_bool(np, "xenon,phy-slow-mode")) >> + params->slow_mode = true; >> + else >> + params->slow_mode = false; >> + >> + if (!of_property_read_u32(np, "xenon,phy-znr", &value)) >> + params->znr = value & ZNR_MASK; >> + else >> + params->znr = ZNR_DEF_VALUE; >> + >> + if (!of_property_read_u32(np, "xenon,phy-zpr", &value)) >> + params->zpr = value & ZPR_MASK; >> + else >> + params->zpr = ZPR_DEF_VALUE; >> + >> + if (!of_property_read_u32(np, "xenon,phy-nr-tun-times", &value)) >> + params->nr_tun_times = value & TUN_CONSECUTIVE_TIMES_MASK; >> + else >> + params->nr_tun_times = TUN_CONSECUTIVE_TIMES; >> + >> + if (!of_property_read_u32(np, "xenon,phy-tun-step-divider", &value)) >> + params->tun_step_divider = value & 0xFF; >> + else >> + params->tun_step_divider = TUNING_STEP_DIVIDER; >> + >> + return get_dt_pad_ctrl_data(host, np, params); >> +} >> + >> +/* >> + * SDH PHY configuration and operations >> + */ >> +static int xenon_sdh_phy_set_fix_sampl_delay(struct sdhci_host *host, >> + unsigned int delay, bool invert) >> +{ >> + u32 reg; >> + unsigned long flags; >> + int ret; >> + >> + if (invert) >> + invert = 0x1; >> + else >> + invert = 0x0; >> + >> + spin_lock_irqsave(&host->lock, flags); >> + >> + /* Disable SDCLK */ >> + reg = sdhci_readl(host, SDHCI_CLOCK_CONTROL); >> + reg &= ~(SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_INT_EN); >> + sdhci_writel(host, reg, SDHCI_CLOCK_CONTROL); >> + >> + udelay(200); >> + >> + /* Setup Sampling fix delay */ >> + reg = sdhci_readl(host, SDHC_SLOT_OP_STATUS_CTRL); >> + reg &= ~(SDH_PHY_FIXED_DELAY_MASK | >> + (0x1 << FORCE_SEL_INVERSE_CLK_SHIFT)); >> + reg |= ((delay & SDH_PHY_FIXED_DELAY_MASK) | >> + (invert << FORCE_SEL_INVERSE_CLK_SHIFT)); >> + sdhci_writel(host, reg, SDHC_SLOT_OP_STATUS_CTRL); >> + >> + /* Enable SD internal clock */ >> + ret = enable_xenon_internal_clk(host); >> + >> + /* Enable SDCLK */ >> + reg = sdhci_readl(host, SDHCI_CLOCK_CONTROL); >> + reg |= SDHCI_CLOCK_CARD_EN; >> + sdhci_writel(host, reg, SDHCI_CLOCK_CONTROL); >> + >> + udelay(200); >> + >> + spin_unlock_irqrestore(&host->lock, flags); >> + return ret; >> +} >> + >> +static int sdh_phy_do_fix_sampl_delay(struct sdhci_host *host, >> + struct mmc_card *card, >> + unsigned int delay, bool invert) >> +{ >> + int ret; >> + >> + xenon_sdh_phy_set_fix_sampl_delay(host, delay, invert); >> + >> + ret = xenon_delay_adj_test(card); >> + if (ret) { >> + dev_dbg(mmc_dev(host->mmc), >> + "fail when sampling fix delay = %d, phase = %d degree\n", >> + delay, invert * 180); >> + return -1; >> + } >> + return 0; >> +} >> + >> +#define SDH_PHY_COARSE_FIX_DELAY (SDH_PHY_FIXED_DELAY_MASK / 2) >> +#define SDH_PHY_FINE_FIX_DELAY (SDH_PHY_COARSE_FIX_DELAY / 4) >> + >> +static int xenon_sdh_phy_fix_sampl_delay_adj(struct sdhci_host *host, >> + struct mmc_card *card) >> +{ >> + u32 reg; >> + bool dll_enable = false; >> + unsigned int min_delay, max_delay, delay; >> + const bool sampl_edge[] = { >> + false, >> + true, >> + }; >> + int i, nr; >> + int ret; >> + >> + if (host->clock > HIGH_SPEED_MAX_DTR) { >> + /* Enable DLL when SDCLK is higher than 50MHz */ >> + reg = sdhci_readl(host, SDH_PHY_SLOT_DLL_CTRL); >> + if (!(reg & SDH_PHY_ENABLE_DLL)) { >> + reg |= (SDH_PHY_ENABLE_DLL | SDH_PHY_FAST_LOCK_EN); >> + sdhci_writel(host, reg, SDH_PHY_SLOT_DLL_CTRL); >> + mdelay(1); >> + >> + reg = sdhci_readl(host, SDH_PHY_SLOT_DLL_PHASE_SEL); >> + reg |= SDH_PHY_DLL_UPDATE_TUNING; >> + sdhci_writel(host, reg, SDH_PHY_SLOT_DLL_PHASE_SEL); >> + } >> + dll_enable = true; >> + } >> + >> + nr = dll_enable ? ARRAY_SIZE(sampl_edge) : 1; >> + for (i = 0; i < nr; i++) { >> + for (min_delay = 0; min_delay <= SDH_PHY_FIXED_DELAY_MASK; >> + min_delay += SDH_PHY_COARSE_FIX_DELAY) { >> + ret = sdh_phy_do_fix_sampl_delay(host, card, min_delay, >> + sampl_edge[i]); >> + if (!ret) >> + break; >> + } >> + >> + if (ret) { >> + dev_dbg(mmc_dev(host->mmc), >> + "Fail to set Fixed Sampling Delay with %s edge\n", >> + sampl_edge[i] ? "negative" : "positive"); >> + continue; >> + } >> + >> + for (max_delay = min_delay + SDH_PHY_FINE_FIX_DELAY; >> + max_delay < SDH_PHY_FIXED_DELAY_MASK; >> + max_delay += SDH_PHY_FINE_FIX_DELAY) { >> + ret = sdh_phy_do_fix_sampl_delay(host, card, max_delay, >> + sampl_edge[i]); >> + if (ret) { >> + max_delay -= SDH_PHY_FINE_FIX_DELAY; >> + break; >> + } >> + } >> + >> + if (!ret) { >> + delay = SDH_PHY_FIXED_DELAY_MASK; >> + ret = sdh_phy_do_fix_sampl_delay(host, card, delay, >> + sampl_edge[i]); >> + if (!ret) >> + max_delay = SDH_PHY_FIXED_DELAY_MASK; >> + } >> + >> + if ((max_delay - min_delay) <= SDH_PHY_FIXED_DELAY_WINDOW_MIN) { >> + dev_info(mmc_dev(host->mmc), >> + "The window size %d with %s edge is too small\n", >> + max_delay - min_delay, >> + sampl_edge[i] ? "negative" : "positive"); >> + continue; >> + } >> + >> + delay = (min_delay + max_delay) / 2; >> + xenon_sdh_phy_set_fix_sampl_delay(host, delay, sampl_edge[i]); >> + dev_dbg(mmc_dev(host->mmc), "sampling fix delay = %d with %s edge\n", >> + delay, sampl_edge[i] ? "negative" : "positive"); >> + return 0; >> + } >> + return -EIO; >> +} >> + >> +static const struct xenon_phy_ops sdh_phy_ops = { >> + .fix_sampl_delay_adj = xenon_sdh_phy_fix_sampl_delay_adj, >> +}; >> + >> +static int alloc_sdh_phy(struct sdhci_xenon_priv *priv) >> +{ >> + priv->phy_params = NULL; >> + priv->phy_ops = &sdh_phy_ops; >> + return 0; >> +} >> + >> +/* >> + * Common functions for all PHYs >> + */ >> +void xenon_soc_pad_ctrl(struct sdhci_host *host, >> + unsigned char signal_voltage) >> +{ >> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >> + struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); >> + >> + if (priv->phy_ops->set_soc_pad) >> + priv->phy_ops->set_soc_pad(host, signal_voltage); >> +} >> + >> +static int __xenon_emmc_delay_adj_test(struct mmc_card *card) >> +{ >> + int err; >> + u8 *ext_csd = NULL; >> + >> + err = mmc_get_ext_csd(card, &ext_csd); >> + kfree(ext_csd); >> + >> + return err; >> +} >> + >> +static int __xenon_sdio_delay_adj_test(struct mmc_card *card) >> +{ >> + struct mmc_command cmd = {0}; >> + int err; >> + >> + cmd.opcode = SD_IO_RW_DIRECT; >> + cmd.flags = MMC_RSP_R5 | MMC_CMD_AC; >> + >> + err = mmc_wait_for_cmd(card->host, &cmd, 0); >> + if (err) >> + return err; >> + >> + if (cmd.resp[0] & R5_ERROR) >> + return -EIO; >> + if (cmd.resp[0] & R5_FUNCTION_NUMBER) >> + return -EINVAL; >> + if (cmd.resp[0] & R5_OUT_OF_RANGE) >> + return -ERANGE; >> + return 0; >> +} >> + >> +static int __xenon_sd_delay_adj_test(struct mmc_card *card) >> +{ >> + struct mmc_command cmd = {0}; >> + int err; >> + >> + cmd.opcode = MMC_SEND_STATUS; >> + cmd.arg = card->rca << 16; >> + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; >> + >> + err = mmc_wait_for_cmd(card->host, &cmd, 0); >> + return err; >> +} >> + >> +static int xenon_delay_adj_test(struct mmc_card *card) >> +{ >> + WARN_ON(!card); >> + WARN_ON(!card->host); >> + >> + if (mmc_card_mmc(card)) >> + return __xenon_emmc_delay_adj_test(card); >> + else if (mmc_card_sd(card)) >> + return __xenon_sd_delay_adj_test(card); >> + else if (mmc_card_sdio(card)) >> + return __xenon_sdio_delay_adj_test(card); >> + else >> + return -EINVAL; >> +} >> + >> +static void xenon_phy_set(struct sdhci_host *host, unsigned char timing) >> +{ >> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >> + struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); >> + >> + if (priv->phy_ops->phy_set) >> + priv->phy_ops->phy_set(host, timing); >> +} >> + >> +static void xenon_hs400_strobe_delay_adj(struct sdhci_host *host, >> + struct mmc_card *card) >> +{ >> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >> + struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); >> + >> + if (WARN_ON(!mmc_card_hs400(card))) >> + return; >> + >> + /* Enable the DLL to automatically adjust HS400 strobe delay. >> + */ >> + if (priv->phy_ops->strobe_delay_adj) >> + priv->phy_ops->strobe_delay_adj(host, card); >> +} >> + >> +static int xenon_fix_sampl_delay_adj(struct sdhci_host *host, >> + struct mmc_card *card) >> +{ >> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >> + struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); >> + >> + if (priv->phy_ops->fix_sampl_delay_adj) >> + return priv->phy_ops->fix_sampl_delay_adj(host, card); >> + >> + return 0; >> +} >> + >> +/* >> + * xenon_delay_adj should not be called inside IRQ context, >> + * either Hard IRQ or Softirq. >> + */ >> +static int xenon_hs_delay_adj(struct sdhci_host *host, >> + struct mmc_card *card) >> +{ >> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >> + struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); >> + int ret = 0; >> + >> + if (WARN_ON(host->clock <= DEFAULT_SDCLK_FREQ)) >> + return -EINVAL; >> + >> + if (mmc_card_hs400(card)) { >> + xenon_hs400_strobe_delay_adj(host, card); >> + return 0; >> + } >> + >> + if (((priv->phy_type == EMMC_5_1_PHY) || >> + (priv->phy_type == EMMC_5_0_PHY)) && >> + (mmc_card_hs200(card) || >> + (host->timing == MMC_TIMING_UHS_SDR104))) { >> + ret = xenon_emmc_phy_config_tuning(host); >> + if (!ret) >> + return 0; >> + } >> + >> + ret = xenon_fix_sampl_delay_adj(host, card); >> + if (ret) >> + dev_err(mmc_dev(host->mmc), "fails sampling fixed delay adjustment\n"); >> + return ret; >> +} >> + >> +int xenon_phy_adj(struct sdhci_host *host, struct mmc_ios *ios) >> +{ >> + struct mmc_host *mmc = host->mmc; >> + struct mmc_card *card; >> + int ret = 0; >> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >> + struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); >> + >> + if (!host->clock) { >> + priv->clock = 0; >> + return 0; >> + } >> + >> + /* >> + * The timing, frequency or bus width is changed, >> + * better to set eMMC PHY based on current setting >> + * and adjust Xenon SDHC delay. >> + */ >> + if ((host->clock == priv->clock) && >> + (ios->bus_width == priv->bus_width) && >> + (ios->timing == priv->timing)) >> + return 0; >> + >> + xenon_phy_set(host, ios->timing); >> + >> + /* Update the record */ >> + priv->bus_width = ios->bus_width; >> + /* Temp stage from HS200 to HS400 */ >> + if (((priv->timing == MMC_TIMING_MMC_HS200) && >> + (ios->timing == MMC_TIMING_MMC_HS)) || >> + ((ios->timing == MMC_TIMING_MMC_HS) && >> + (priv->clock > host->clock))) { >> + priv->timing = ios->timing; >> + priv->clock = host->clock; >> + return 0; >> + } >> + priv->timing = ios->timing; >> + priv->clock = host->clock; >> + >> + /* Legacy mode is a special case */ >> + if (ios->timing == MMC_TIMING_LEGACY) >> + return 0; >> + >> + card = priv->card_candidate; >> + if (unlikely(!card)) { >> + dev_warn(mmc_dev(mmc), "card is not present\n"); >> + return -EINVAL; >> + } >> + >> + if (host->clock > DEFAULT_SDCLK_FREQ) >> + ret = xenon_hs_delay_adj(host, card); >> + return ret; >> +} >> + >> +static int add_xenon_phy(struct device_node *np, struct sdhci_host *host, >> + const char *phy_name) >> +{ >> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >> + struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); >> + int i, ret; >> + >> + for (i = 0; i < NR_PHY_TYPES; i++) { >> + if (!strcmp(phy_name, phy_types[i])) { >> + priv->phy_type = i; >> + break; >> + } >> + } >> + if (i == NR_PHY_TYPES) { >> + dev_err(mmc_dev(host->mmc), >> + "Unable to determine PHY name %s. Use default eMMC 5.1 PHY\n", >> + phy_name); >> + priv->phy_type = EMMC_5_1_PHY; >> + } >> + >> + if (priv->phy_type == SDH_PHY) { >> + return alloc_sdh_phy(priv); >> + } else if ((priv->phy_type == EMMC_5_0_PHY) || >> + (priv->phy_type == EMMC_5_1_PHY)) { >> + ret = alloc_emmc_phy(priv); >> + if (ret) >> + return ret; >> + return emmc_phy_parse_param_dt(host, np, priv->phy_params); >> + } >> + >> + return -EINVAL; >> +} >> + >> +int xenon_phy_parse_dt(struct device_node *np, struct sdhci_host *host) >> +{ >> + const char *phy_type = NULL; >> + >> + if (!of_property_read_string(np, "xenon,phy-type", &phy_type)) >> + return add_xenon_phy(np, host, phy_type); >> + >> + dev_err(mmc_dev(host->mmc), "Fail to get Xenon PHY type. Use default eMMC 5.1 PHY\n"); >> + return add_xenon_phy(np, host, "emmc 5.1 phy"); >> +} >> diff --git a/drivers/mmc/host/sdhci-xenon-phy.h b/drivers/mmc/host/sdhci-xenon-phy.h >> new file mode 100644 >> index 000000000000..4373c71d3b7b >> --- /dev/null >> +++ b/drivers/mmc/host/sdhci-xenon-phy.h >> @@ -0,0 +1,157 @@ >> +/* linux/drivers/mmc/host/sdhci-xenon-phy.h >> + * >> + * Author: Hu Ziji >> + * Date: 2016-8-24 >> + * >> + * Copyright (C) 2016 Marvell, All Rights Reserved. >> + * >> + * This program is free software; you can redistribute it and/or modify >> + * it under the terms of the GNU General Public License as published by >> + * the Free Software Foundation; either version 2 of the License, or (at >> + * your option) any later version. >> + */ >> +#ifndef SDHCI_XENON_PHY_H_ >> +#define SDHCI_XENON_PHY_H_ >> + >> +#include >> +#include "sdhci.h" >> + >> +/* Register base for eMMC PHY 5.0 Version */ >> +#define EMMC_5_0_PHY_REG_BASE 0x0160 >> +/* Register base for eMMC PHY 5.1 Version */ >> +#define EMMC_PHY_REG_BASE 0x0170 >> + >> +#define EMMC_PHY_TIMING_ADJUST EMMC_PHY_REG_BASE >> +#define EMMC_5_0_PHY_TIMING_ADJUST EMMC_5_0_PHY_REG_BASE >> +#define TIMING_ADJUST_SLOW_MODE BIT(29) >> +#define TIMING_ADJUST_SDIO_MODE BIT(28) >> +#define OUTPUT_QSN_PHASE_SELECT BIT(17) >> +#define SAMPL_INV_QSP_PHASE_SELECT BIT(18) >> +#define SAMPL_INV_QSP_PHASE_SELECT_SHIFT 18 >> +#define PHY_INITIALIZAION BIT(31) >> +#define WAIT_CYCLE_BEFORE_USING_MASK 0xF >> +#define WAIT_CYCLE_BEFORE_USING_SHIFT 12 >> +#define FC_SYNC_EN_DURATION_MASK 0xF >> +#define FC_SYNC_EN_DURATION_SHIFT 8 >> +#define FC_SYNC_RST_EN_DURATION_MASK 0xF >> +#define FC_SYNC_RST_EN_DURATION_SHIFT 4 >> +#define FC_SYNC_RST_DURATION_MASK 0xF >> +#define FC_SYNC_RST_DURATION_SHIFT 0 >> + >> +#define EMMC_PHY_FUNC_CONTROL (EMMC_PHY_REG_BASE + 0x4) >> +#define EMMC_5_0_PHY_FUNC_CONTROL (EMMC_5_0_PHY_REG_BASE + 0x4) >> +#define ASYNC_DDRMODE_MASK BIT(23) >> +#define ASYNC_DDRMODE_SHIFT 23 >> +#define CMD_DDR_MODE BIT(16) >> +#define DQ_DDR_MODE_SHIFT 8 >> +#define DQ_DDR_MODE_MASK 0xFF >> +#define DQ_ASYNC_MODE BIT(4) >> + >> +#define EMMC_PHY_PAD_CONTROL (EMMC_PHY_REG_BASE + 0x8) >> +#define EMMC_5_0_PHY_PAD_CONTROL (EMMC_5_0_PHY_REG_BASE + 0x8) >> +#define REC_EN_SHIFT 24 >> +#define REC_EN_MASK 0xF >> +#define FC_DQ_RECEN BIT(24) >> +#define FC_CMD_RECEN BIT(25) >> +#define FC_QSP_RECEN BIT(26) >> +#define FC_QSN_RECEN BIT(27) >> +#define OEN_QSN BIT(28) >> +#define AUTO_RECEN_CTRL BIT(30) >> +#define FC_ALL_CMOS_RECEIVER 0xF000 >> + >> +#define EMMC5_FC_QSP_PD BIT(18) >> +#define EMMC5_FC_QSP_PU BIT(22) >> +#define EMMC5_FC_CMD_PD BIT(17) >> +#define EMMC5_FC_CMD_PU BIT(21) >> +#define EMMC5_FC_DQ_PD BIT(16) >> +#define EMMC5_FC_DQ_PU BIT(20) >> + >> +#define EMMC_PHY_PAD_CONTROL1 (EMMC_PHY_REG_BASE + 0xC) >> +#define EMMC5_1_FC_QSP_PD BIT(9) >> +#define EMMC5_1_FC_QSP_PU BIT(25) >> +#define EMMC5_1_FC_CMD_PD BIT(8) >> +#define EMMC5_1_FC_CMD_PU BIT(24) >> +#define EMMC5_1_FC_DQ_PD 0xFF >> +#define EMMC5_1_FC_DQ_PU (0xFF << 16) >> + >> +#define EMMC_PHY_PAD_CONTROL2 (EMMC_PHY_REG_BASE + 0x10) >> +#define EMMC_5_0_PHY_PAD_CONTROL2 (EMMC_5_0_PHY_REG_BASE + 0xC) >> +#define ZNR_MASK 0x1F >> +#define ZNR_SHIFT 8 >> +#define ZPR_MASK 0x1F >> +/* Perferred ZNR and ZPR value vary between different boards. >> + * The specific ZNR and ZPR value should be defined here >> + * according to board actual timing. >> + */ >> +#define ZNR_DEF_VALUE 0xF >> +#define ZPR_DEF_VALUE 0xF >> + >> +#define EMMC_PHY_DLL_CONTROL (EMMC_PHY_REG_BASE + 0x14) >> +#define EMMC_5_0_PHY_DLL_CONTROL (EMMC_5_0_PHY_REG_BASE + 0x10) >> +#define DLL_ENABLE BIT(31) >> +#define DLL_UPDATE_STROBE_5_0 BIT(30) >> +#define DLL_REFCLK_SEL BIT(30) >> +#define DLL_UPDATE BIT(23) >> +#define DLL_PHSEL1_SHIFT 24 >> +#define DLL_PHSEL0_SHIFT 16 >> +#define DLL_PHASE_MASK 0x3F >> +#define DLL_PHASE_90_DEGREE 0x1F >> +#define DLL_FAST_LOCK BIT(5) >> +#define DLL_GAIN2X BIT(3) >> +#define DLL_BYPASS_EN BIT(0) >> + >> +#define EMMC_5_0_PHY_LOGIC_TIMING_ADJUST (EMMC_5_0_PHY_REG_BASE + 0x14) >> +#define EMMC_PHY_LOGIC_TIMING_ADJUST (EMMC_PHY_REG_BASE + 0x18) >> + >> +enum sampl_fix_delay_phase { >> + PHASE_0_DEGREE = 0x0, >> + PHASE_90_DEGREE = 0x1, >> + PHASE_180_DEGREE = 0x2, >> + PHASE_270_DEGREE = 0x3, >> +}; >> + >> +#define SDH_PHY_SLOT_DLL_CTRL (0x0138) >> +#define SDH_PHY_ENABLE_DLL BIT(1) >> +#define SDH_PHY_FAST_LOCK_EN BIT(5) >> + >> +#define SDH_PHY_SLOT_DLL_PHASE_SEL (0x013C) >> +#define SDH_PHY_DLL_UPDATE_TUNING BIT(15) >> + >> +enum soc_pad_ctrl_type { >> + SOC_PAD_SD, >> + SOC_PAD_FIXED_1_8V, >> +}; >> + >> +/* >> + * List offset of PHY registers and some special register values >> + * in eMMC PHY 5.0 or eMMC PHY 5.1 >> + */ >> +struct xenon_emmc_phy_regs { >> + /* Offset of Timing Adjust register */ >> + u16 timing_adj; >> + /* Offset of Func Control register */ >> + u16 func_ctrl; >> + /* Offset of Pad Control register */ >> + u16 pad_ctrl; >> + /* Offset of Pad Control register */ >> + u16 pad_ctrl2; >> + /* Offset of DLL Control register */ >> + u16 dll_ctrl; >> + /* Offset of Logic Timing Adjust register */ >> + u16 logic_timing_adj; >> + /* Max value of eMMC Fixed Sampling Delay */ >> + u32 delay_mask; >> + /* DLL Update Enable bit */ >> + u32 dll_update; >> +}; >> + >> +struct xenon_phy_ops { >> + void (*strobe_delay_adj)(struct sdhci_host *host, >> + struct mmc_card *card); >> + int (*fix_sampl_delay_adj)(struct sdhci_host *host, >> + struct mmc_card *card); >> + void (*phy_set)(struct sdhci_host *host, unsigned char timing); >> + void (*set_soc_pad)(struct sdhci_host *host, >> + unsigned char signal_voltage); >> +}; >> +#endif >> diff --git a/drivers/mmc/host/sdhci-xenon.c b/drivers/mmc/host/sdhci-xenon.c >> index 03ba183494d3..4d7d871544fc 100644 >> --- a/drivers/mmc/host/sdhci-xenon.c >> +++ b/drivers/mmc/host/sdhci-xenon.c >> @@ -224,6 +224,7 @@ static void xenon_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) >> spin_unlock_irqrestore(&host->lock, flags); >> >> sdhci_set_ios(mmc, ios); >> + xenon_phy_adj(host, ios); >> >> if (host->clock > DEFAULT_SDCLK_FREQ) { >> spin_lock_irqsave(&host->lock, flags); >> @@ -309,6 +310,8 @@ static int xenon_start_signal_voltage_switch(struct mmc_host *mmc, >> */ >> enable_xenon_internal_clk(host); >> >> + xenon_soc_pad_ctrl(host, ios->signal_voltage); >> + >> if (priv->card_candidate) { >> if (mmc_card_mmc(priv->card_candidate)) >> return xenon_emmc_signal_voltage_switch(mmc, ios); >> @@ -453,6 +456,7 @@ static int xenon_probe_dt(struct platform_device *pdev) >> sdhci_writel(host, reg, SDHC_SYS_EXT_OP_CTRL); >> } >> >> + err = xenon_phy_parse_dt(np, host); >> return err; >> } >> >> diff --git a/drivers/mmc/host/sdhci-xenon.h b/drivers/mmc/host/sdhci-xenon.h >> index c2370493fbe8..06e5261a563c 100644 >> --- a/drivers/mmc/host/sdhci-xenon.h >> +++ b/drivers/mmc/host/sdhci-xenon.h >> @@ -15,6 +15,7 @@ >> #include >> #include >> #include "sdhci.h" >> +#include "sdhci-xenon-phy.h" >> >> /* Register Offset of SD Host Controller SOCP self-defined register */ >> #define SDHC_SYS_CFG_INFO 0x0104 >> @@ -76,6 +77,7 @@ >> #define MMC_TIMING_FAKE 0xFF >> >> #define DEFAULT_SDCLK_FREQ (400000) >> +#define LOWEST_SDCLK_FREQ (100000) >> >> /* Xenon specific Mode Select value */ >> #define XENON_SDHCI_CTRL_HS200 0x5 >> @@ -97,6 +99,15 @@ struct sdhci_xenon_priv { >> /* Slot idx */ >> u8 slot_idx; >> >> + int phy_type; >> + /* >> + * Contains board-specific PHY parameters >> + * passed from device tree. >> + */ >> + void *phy_params; >> + const struct xenon_phy_ops *phy_ops; >> + struct xenon_emmc_phy_regs *emmc_phy_regs; >> + >> /* >> * When initializing card, Xenon has to determine card type and >> * adjust Sampling Fixed delay. >> @@ -131,4 +142,10 @@ static inline int enable_xenon_internal_clk(struct sdhci_host *host) >> >> return 0; >> } >> + >> +int xenon_phy_adj(struct sdhci_host *host, struct mmc_ios *ios); >> +int xenon_phy_parse_dt(struct device_node *np, >> + struct sdhci_host *host); >> +void xenon_soc_pad_ctrl(struct sdhci_host *host, >> + unsigned char signal_voltage); >> #endif >> > >