From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.4 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH, MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,UNPARSEABLE_RELAY, URIBL_BLOCKED,USER_AGENT_SANE_2 autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D835DC4727F for ; Fri, 25 Sep 2020 10:25:48 +0000 (UTC) Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 74F292075E for ; Fri, 25 Sep 2020 10:25:48 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="P+G8kTky"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="N8wJCbgX" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 74F292075E Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-mediatek-bounces+linux-mediatek=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:Cc:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Date:To:From: Subject:Message-ID:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=omLNq2zwkAgJm6uvAfJ3V0PhPUGKD8koD0zS0q2wtfU=; b=P+G8kTkymSYM+8fNUcKz3jF0v KCcRjmo/FRIxjU3pqUB2pBOYDEl9Ll6+1/9ES0RcTr5fhlSBrktQ0iK7pCn56b5e50/bFIENn4xKz TipHZn4vV+8kogBC1PLUd24mvRVaAHUu4wFkYMLeMfeu2ujRwJpgHzTZYnhcjdyurGSsxPNe0JWPq GnjRN/zHXLb2YZqwpErfte4xiTIyqm8MGDLb80e0y5NT3oP+SCLv73vRaeUATFO9xDIAU0vDZnIAo 6lNhb6JcS0okYJaBmFqI9gPXZsvQsa7VZipoH1CGQXR9Grd+mIAG9GLOgHsLa5QziuHafTNvq7oUC sqcDlVi9Q==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1kLkv1-0005at-6L; Fri, 25 Sep 2020 10:25:35 +0000 Received: from mailgw02.mediatek.com ([216.200.240.185]) by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1kLkux-0005a9-Ip; Fri, 25 Sep 2020 10:25:33 +0000 X-UUID: cd54fcda55e44bac996c6519d506c8c7-20200925 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Transfer-Encoding:MIME-Version:Content-Type:References:In-Reply-To:Date:CC:To:From:Subject:Message-ID; bh=furd6J9lKYw7rEQJct0IXtstQo7k4wrpljtEUJ2R3XM=; b=N8wJCbgXUmJTijCMnBU1JdtQUxzkc8/F7ijdUUzpmXT+UInL5DGxgRg/K6Zo235bcYtcKD51h3aPta8hspDOLVgtQylyyWtuCRjHSdXkgjIxxM95GM+FJ3iPyZOMJ4djGyc+IyPVcLLb8vknBZuOUBbQjU/X0BFlCWc3lNotLIM=; X-UUID: cd54fcda55e44bac996c6519d506c8c7-20200925 Received: from mtkcas66.mediatek.inc [(172.29.193.44)] by mailgw02.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 815120003; Fri, 25 Sep 2020 02:25:25 -0800 Received: from mtkmbs05n2.mediatek.inc (172.21.101.140) by MTKMBS62N2.mediatek.inc (172.29.193.42) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Fri, 25 Sep 2020 03:25:23 -0700 Received: from MTKCAS06.mediatek.inc (172.21.101.30) by mtkmbs05n2.mediatek.inc (172.21.101.140) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Fri, 25 Sep 2020 18:25:21 +0800 Received: from [172.21.77.4] (172.21.77.4) by MTKCAS06.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Fri, 25 Sep 2020 18:25:21 +0800 Message-ID: <1601029522.1346.53.camel@mtksdaap41> Subject: Re: [PATCH 02/12] soc: mediatek: Add MediaTek SCPSYS power domains From: Weiyi Lu To: Enric Balletbo i Serra Date: Fri, 25 Sep 2020 18:25:22 +0800 In-Reply-To: <20200910172826.3074357-3-enric.balletbo@collabora.com> References: <20200910172826.3074357-1-enric.balletbo@collabora.com> <20200910172826.3074357-3-enric.balletbo@collabora.com> X-Mailer: Evolution 3.10.4-0ubuntu2 MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200925_062531_877383_7D18C8FF X-CRM114-Status: GOOD ( 28.18 ) X-BeenThere: linux-mediatek@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: drinkcat@chromium.org, linux-kernel@vger.kernel.org, fparent@baylibre.com, Matthias Brugger , linux-mediatek@lists.infradead.org, hsinyi@chromium.org, matthias.bgg@gmail.com, Collabora Kernel ML , linux-arm-kernel@lists.infradead.org Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "Linux-mediatek" Errors-To: linux-mediatek-bounces+linux-mediatek=archiver.kernel.org@lists.infradead.org On Thu, 2020-09-10 at 19:28 +0200, Enric Balletbo i Serra wrote: > The System Control Processor System (SCPSYS) has several power management > related tasks in the system. This driver implements support to handle > the different power domains supported in order to meet high performance > and low power requirements. > > Co-developed-by: Matthias Brugger > Signed-off-by: Matthias Brugger > Signed-off-by: Enric Balletbo i Serra > --- > > drivers/soc/mediatek/Kconfig | 13 + > drivers/soc/mediatek/Makefile | 1 + > drivers/soc/mediatek/mtk-pm-domains.c | 626 ++++++++++++++++++++++++++ > 3 files changed, 640 insertions(+) > create mode 100644 drivers/soc/mediatek/mtk-pm-domains.c > > diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig > index 59a56cd790ec..68d800f9e4a5 100644 > --- a/drivers/soc/mediatek/Kconfig > +++ b/drivers/soc/mediatek/Kconfig > @@ -44,6 +44,19 @@ config MTK_SCPSYS > Say yes here to add support for the MediaTek SCPSYS power domain > driver. > > +config MTK_SCPSYS_PM_DOMAINS > + bool "MediaTek SCPSYS generic power domain" > + default ARCH_MEDIATEK > + depends on PM > + depends on MTK_INFRACFG > + select PM_GENERIC_DOMAINS > + select REGMAP > + help > + Say y here to enable power domain support. > + In order to meet high performance and low power requirements, the System > + Control Processor System (SCPSYS) has several power management related > + tasks in the system. > + > config MTK_MMSYS > bool "MediaTek MMSYS Support" > default ARCH_MEDIATEK > diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile > index 01f9f873634a..1e60fb4f89d4 100644 > --- a/drivers/soc/mediatek/Makefile > +++ b/drivers/soc/mediatek/Makefile > @@ -3,4 +3,5 @@ obj-$(CONFIG_MTK_CMDQ) += mtk-cmdq-helper.o > obj-$(CONFIG_MTK_INFRACFG) += mtk-infracfg.o > obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o > obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o > +obj-$(CONFIG_MTK_SCPSYS_PM_DOMAINS) += mtk-pm-domains.o > obj-$(CONFIG_MTK_MMSYS) += mtk-mmsys.o > diff --git a/drivers/soc/mediatek/mtk-pm-domains.c b/drivers/soc/mediatek/mtk-pm-domains.c > new file mode 100644 > index 000000000000..db631dbaf2e3 > --- /dev/null > +++ b/drivers/soc/mediatek/mtk-pm-domains.c > @@ -0,0 +1,626 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * Copyright (c) 2020 Collabora Ltd. > + */ > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > + > +#define MTK_POLL_DELAY_US 10 > +#define MTK_POLL_TIMEOUT USEC_PER_SEC > + > +#define MTK_SCPD_ACTIVE_WAKEUP BIT(0) > +#define MTK_SCPD_FWAIT_SRAM BIT(1) > +#define MTK_SCPD_CAPS(_scpd, _x) ((_scpd)->data->caps & (_x)) > + > +#define SPM_VDE_PWR_CON 0x0210 > +#define SPM_MFG_PWR_CON 0x0214 > +#define SPM_VEN_PWR_CON 0x0230 > +#define SPM_ISP_PWR_CON 0x0238 > +#define SPM_DIS_PWR_CON 0x023c > +#define SPM_VEN2_PWR_CON 0x0298 > +#define SPM_AUDIO_PWR_CON 0x029c > +#define SPM_MFG_2D_PWR_CON 0x02c0 > +#define SPM_MFG_ASYNC_PWR_CON 0x02c4 > +#define SPM_USB_PWR_CON 0x02cc > + If me, I'd choose to write directly into the data of each SoC now because it's inconsistent on most MediatTek chips. > +#define SPM_PWR_STATUS 0x060c > +#define SPM_PWR_STATUS_2ND 0x0610 > + > +#define PWR_RST_B_BIT BIT(0) > +#define PWR_ISO_BIT BIT(1) > +#define PWR_ON_BIT BIT(2) > +#define PWR_ON_2ND_BIT BIT(3) > +#define PWR_CLK_DIS_BIT BIT(4) > + > +#define PWR_STATUS_DISP BIT(3) > +#define PWR_STATUS_MFG BIT(4) > +#define PWR_STATUS_ISP BIT(5) > +#define PWR_STATUS_VDEC BIT(7) > +#define PWR_STATUS_VENC_LT BIT(20) > +#define PWR_STATUS_VENC BIT(21) > +#define PWR_STATUS_MFG_2D BIT(22) > +#define PWR_STATUS_MFG_ASYNC BIT(23) > +#define PWR_STATUS_AUDIO BIT(24) > +#define PWR_STATUS_USB BIT(25) > + same here for the status bits. > +struct scpsys_bus_prot_data { > + u32 bus_prot_mask; > + bool bus_prot_reg_update; > +}; > + > +/** > + * struct scpsys_domain_data - scp domain data for power on/off flow > + * @sta_mask: The mask for power on/off status bit. > + * @ctl_offs: The offset for main power control register. > + * @sram_pdn_bits: The mask for sram power control bits. > + * @sram_pdn_ack_bits: The mask for sram power control acked bits. > + * @caps: The flag for active wake-up action. > + * @bp_infracfg: bus protection for infracfg subsystem > + */ > +struct scpsys_domain_data { > + u32 sta_mask; > + int ctl_offs; > + u32 sram_pdn_bits; > + u32 sram_pdn_ack_bits; > + u8 caps; > + const struct scpsys_bus_prot_data bp_infracfg; > +}; > + > +struct scpsys_domain { > + struct generic_pm_domain genpd; > + const struct scpsys_domain_data *data; > + struct scpsys *scpsys; > + int num_clks; > + struct clk_bulk_data *clks; > + struct regmap *infracfg; Could we move struct regmap *infracfg; back to struct scpsys? It seems we need to set this property many times under each power domain sub node in device tree? > +}; > + > +struct scpsys_soc_data { > + const struct scpsys_domain_data *domains; > + int num_domains; > + int pwr_sta_offs; > + int pwr_sta2nd_offs; > +}; > + > +struct scpsys { > + struct device *dev; > + void __iomem *base; > + const struct scpsys_soc_data *soc_data; > + struct genpd_onecell_data pd_data; > + struct generic_pm_domain *domains[]; > +}; > + > +#define to_scpsys_domain(gpd) container_of(gpd, struct scpsys_domain, genpd) > + > +static int scpsys_domain_is_on(struct scpsys_domain *pd) > +{ > + struct scpsys *scpsys = pd->scpsys; > + > + u32 status = readl(scpsys->base + scpsys->soc_data->pwr_sta_offs) & pd->data->sta_mask; > + u32 status2 = readl(scpsys->base + scpsys->soc_data->pwr_sta2nd_offs) & pd->data->sta_mask; > + > + /* > + * A domain is on when both status bits are set. If only one is set > + * return an error. This happens while powering up a domain > + */ > + > + if (status && status2) > + return true; > + if (!status && !status2) > + return false; > + > + return -EINVAL; > +} > + > +static int scpsys_sram_enable(struct scpsys_domain *pd, void __iomem *ctl_addr) > +{ > + u32 pdn_ack = pd->data->sram_pdn_ack_bits; > + u32 val; > + int tmp; > + int ret; > + > + val = readl(ctl_addr); > + val &= ~pd->data->sram_pdn_bits; > + writel(val, ctl_addr); > + > + /* Either wait until SRAM_PDN_ACK all 1 or 0 */ > + ret = readl_poll_timeout(ctl_addr, tmp, (tmp & pdn_ack) == 0, MTK_POLL_DELAY_US, > + MTK_POLL_TIMEOUT); > + if (ret < 0) > + return ret; > + > + return 0; > +} > + > +static int scpsys_sram_disable(struct scpsys_domain *pd, void __iomem *ctl_addr) > +{ > + u32 pdn_ack = pd->data->sram_pdn_ack_bits; > + u32 val; > + int tmp; > + > + val = readl(ctl_addr); > + val |= pd->data->sram_pdn_bits; > + writel(val, ctl_addr); > + > + /* Either wait until SRAM_PDN_ACK all 1 or 0 */ > + return readl_poll_timeout(ctl_addr, tmp, (tmp & pdn_ack) == pdn_ack, MTK_POLL_DELAY_US, > + MTK_POLL_TIMEOUT); > +} > + > +static int scpsys_bus_protect_enable(struct scpsys_domain *pd) > +{ > + const struct scpsys_bus_prot_data *bp_data = &pd->data->bp_infracfg; > + > + if (!bp_data->bus_prot_mask) > + return 0; > + > + return mtk_infracfg_set_bus_protection(pd->infracfg, bp_data->bus_prot_mask, > + bp_data->bus_prot_reg_update); > +} > + > +static int scpsys_bus_protect_disable(struct scpsys_domain *pd) > +{ > + const struct scpsys_bus_prot_data *bp_data = &pd->data->bp_infracfg; > + > + if (!bp_data->bus_prot_mask) > + return 0; > + > + return mtk_infracfg_clear_bus_protection(pd->infracfg, bp_data->bus_prot_mask, > + bp_data->bus_prot_reg_update); > +} > + > +static int scpsys_power_on(struct generic_pm_domain *genpd) > +{ > + struct scpsys_domain *pd = container_of(genpd, struct scpsys_domain, genpd); > + struct scpsys *scpsys = pd->scpsys; > + void __iomem *ctl_addr = scpsys->base + pd->data->ctl_offs; > + int ret, tmp; > + u32 val; > + > + ret = clk_bulk_enable(pd->num_clks, pd->clks); > + if (ret) > + return ret; > + > + /* subsys power on */ > + val = readl(ctl_addr); > + val |= PWR_ON_BIT; > + writel(val, ctl_addr); > + val |= PWR_ON_2ND_BIT; > + writel(val, ctl_addr); > + > + /* wait until PWR_ACK = 1 */ > + ret = readx_poll_timeout(scpsys_domain_is_on, pd, tmp, tmp > 0, MTK_POLL_DELAY_US, > + MTK_POLL_TIMEOUT); > + if (ret < 0) > + goto err_pwr_ack; > + > + val &= ~PWR_CLK_DIS_BIT; > + writel(val, ctl_addr); > + > + val &= ~PWR_ISO_BIT; > + writel(val, ctl_addr); > + > + val |= PWR_RST_B_BIT; > + writel(val, ctl_addr); > + > + ret = scpsys_sram_enable(pd, ctl_addr); > + if (ret < 0) > + goto err_pwr_ack; > + > + ret = scpsys_bus_protect_disable(pd); > + if (ret < 0) > + goto err_pwr_ack; > + > + return 0; > + > +err_pwr_ack: > + clk_bulk_disable(pd->num_clks, pd->clks); > + dev_err(scpsys->dev, "Failed to power on domain %s\n", genpd->name); > + > + return ret; > +} > + > +static int scpsys_power_off(struct generic_pm_domain *genpd) > +{ > + struct scpsys_domain *pd = container_of(genpd, struct scpsys_domain, genpd); > + struct scpsys *scpsys = pd->scpsys; > + void __iomem *ctl_addr = scpsys->base + pd->data->ctl_offs; > + int ret, tmp; > + u32 val; > + > + ret = scpsys_bus_protect_enable(pd); > + if (ret < 0) > + return ret; > + > + ret = scpsys_sram_disable(pd, ctl_addr); > + if (ret < 0) > + return ret; > + > + /* subsys power off */ > + val = readl(ctl_addr); > + val |= PWR_ISO_BIT; > + writel(val, ctl_addr); > + > + val &= ~PWR_RST_B_BIT; > + writel(val, ctl_addr); > + > + val |= PWR_CLK_DIS_BIT; > + writel(val, ctl_addr); > + > + val &= ~PWR_ON_BIT; > + writel(val, ctl_addr); > + > + val &= ~PWR_ON_2ND_BIT; > + writel(val, ctl_addr); > + > + /* wait until PWR_ACK = 0 */ > + ret = readx_poll_timeout(scpsys_domain_is_on, pd, tmp, tmp == 0, MTK_POLL_DELAY_US, > + MTK_POLL_TIMEOUT); > + if (ret < 0) > + return ret; > + > + clk_bulk_disable(pd->num_clks, pd->clks); > + > + return 0; > +} > + > +static int scpsys_add_one_domain(struct scpsys *scpsys, struct device_node *node) > +{ > + const struct scpsys_domain_data *domain_data; > + struct scpsys_domain *pd; > + int i, ret; > + u32 id; > + > + ret = of_property_read_u32(node, "reg", &id); > + if (ret) { > + dev_err(scpsys->dev, "%pOFn: failed to retrieve domain id from reg: %d\n", node, > + ret); > + return -EINVAL; > + } > + > + if (id >= scpsys->soc_data->num_domains) { > + dev_err(scpsys->dev, "%pOFn: invalid domain id %d\n", node, id); > + return -EINVAL; > + } > + > + domain_data = &scpsys->soc_data->domains[id]; > + if (!domain_data) { > + dev_err(scpsys->dev, "%pOFn: undefined domain id %d\n", node, id); > + return -EINVAL; > + } > + > + pd = devm_kzalloc(scpsys->dev, sizeof(*pd), GFP_KERNEL); > + if (!pd) > + return -ENOMEM; > + > + pd->data = domain_data; > + pd->scpsys = scpsys; > + > + pd->infracfg = syscon_regmap_lookup_by_phandle(node, "mediatek,infracfg"); > + if (IS_ERR(pd->infracfg)) > + pd->infracfg = NULL; > + > + pd->num_clks = of_clk_get_parent_count(node); > + if (pd->num_clks > 0) { > + pd->clks = devm_kcalloc(scpsys->dev, pd->num_clks, sizeof(*pd->clks), GFP_KERNEL); > + if (!pd->clks) > + return -ENOMEM; > + } else { > + pd->num_clks = 0; > + } > + > + for (i = 0; i < pd->num_clks; i++) { > + pd->clks[i].clk = of_clk_get(node, i); Is it possible to have a better way that we could use of_clk_bulk_get()? > + if (IS_ERR(pd->clks[i].clk)) { > + ret = PTR_ERR(pd->clks[i].clk); > + dev_err(scpsys->dev, "%pOFn: failed to get clk at index %d: %d\n", node, i, > + ret); > + return ret; > + } > + } > + > + ret = clk_bulk_prepare(pd->num_clks, pd->clks); > + if (ret) > + goto err_put_clocks; > + > + /* > + * Initially turn on all domains to make the domains usable > + * with !CONFIG_PM and to get the hardware in sync with the > + * software. The unused domains will be switched off during > + * late_init time. > + */ > + ret = scpsys_power_on(&pd->genpd); > + if (ret < 0) { > + dev_err(scpsys->dev, "failed to power on domain %pOFN with error %d\n", node, ret); > + goto err_unprepare_clocks; > + } > + > + pd->genpd.name = node->name; > + pd->genpd.power_off = scpsys_power_off; > + pd->genpd.power_on = scpsys_power_on; > + > + pm_genpd_init(&pd->genpd, NULL, false); > + > + scpsys->domains[id] = &pd->genpd; > + return 0; > + > +err_unprepare_clocks: > + clk_bulk_unprepare(pd->num_clks, pd->clks); > +err_put_clocks: > + clk_bulk_put(pd->num_clks, pd->clks); > + devm_kfree(scpsys->dev, pd->clks); > + pd->num_clks = 0; > + return ret; > +} > + > +static int scpsys_add_subdomain(struct scpsys *scpsys, struct device_node *parent) > +{ > + struct device_node *child; > + struct generic_pm_domain *child_pd, *parent_pd; > + int ret; > + > + for_each_child_of_node(parent, child) { > + u32 id; > + > + ret = of_property_read_u32(parent, "reg", &id); > + if (ret) { > + dev_err(scpsys->dev, "%pOFn: failed to get parent domain id: %d\n", child, > + ret); > + goto err_put_node; > + } > + parent_pd = scpsys->pd_data.domains[id]; > + nit. Could we move parent outside(in front of) the loop? > + ret = scpsys_add_one_domain(scpsys, child); > + if (ret) { > + dev_err(scpsys->dev, "error adding power domain for %pOFn: %d\n", child, > + ret); > + goto err_put_node; > + } > + > + ret = of_property_read_u32(child, "reg", &id); > + if (ret) { > + dev_err(scpsys->dev, "%pOFn: failed to get child domain id: %d\n", child, > + ret); > + goto err_put_node; > + } > + child_pd = scpsys->pd_data.domains[id]; > + > + ret = pm_genpd_add_subdomain(parent_pd, child_pd); > + if (ret) { > + dev_err(scpsys->dev, "failed to add %s subdomain to parent %s\n", > + child_pd->name, parent_pd->name); > + goto err_put_node; > + } else { > + dev_dbg(scpsys->dev, "%s add subdomain: %s\n", parent_pd->name, > + child_pd->name); > + } > + > + /* recursive call to add all subdomains */ > + ret = scpsys_add_subdomain(scpsys, child); > + if (ret) > + goto err_put_node; > + } > + > + return 0; > + > +err_put_node: > + of_node_put(child); > + return ret; > +} > + > +static void scpsys_remove_one_domain(struct scpsys_domain *pd) > +{ > + int ret; > + > + /* > + * We're in the error cleanup already, so we only complain, > + * but won't emit another error on top of the original one. > + */ > + ret = pm_genpd_remove(&pd->genpd); > + if (ret < 0) > + dev_err(pd->scpsys->dev, > + "failed to remove domain '%s' : %d - state may be inconsistent\n", > + pd->genpd.name, ret); > + > + scpsys_power_off(&pd->genpd); > + > + clk_bulk_unprepare(pd->num_clks, pd->clks); > + clk_bulk_put(pd->num_clks, pd->clks); > + pd->num_clks = 0; > +} > + > +static void scpsys_domain_cleanup(struct scpsys *scpsys) > +{ > + struct generic_pm_domain *genpd; > + struct scpsys_domain *pd; > + int i; > + > + for (i = scpsys->pd_data.num_domains - 1; i >= 0; i--) { > + genpd = scpsys->pd_data.domains[i]; > + if (genpd) { > + pd = to_scpsys_domain(genpd); > + scpsys_remove_one_domain(pd); > + } > + } > +} > + > +/* > + * MT8173 power domain support > + */ > + > +static const struct scpsys_domain_data scpsys_domain_data_mt8173[] = { > + [MT8173_POWER_DOMAIN_VDEC] = { > + .sta_mask = PWR_STATUS_VDEC, > + .ctl_offs = SPM_VDE_PWR_CON, > + .sram_pdn_bits = GENMASK(11, 8), > + .sram_pdn_ack_bits = GENMASK(12, 12), > + }, > + [MT8173_POWER_DOMAIN_VENC] = { > + .sta_mask = PWR_STATUS_VENC, > + .ctl_offs = SPM_VEN_PWR_CON, > + .sram_pdn_bits = GENMASK(11, 8), > + .sram_pdn_ack_bits = GENMASK(15, 12), > + }, > + [MT8173_POWER_DOMAIN_ISP] = { > + .sta_mask = PWR_STATUS_ISP, > + .ctl_offs = SPM_ISP_PWR_CON, > + .sram_pdn_bits = GENMASK(11, 8), > + .sram_pdn_ack_bits = GENMASK(13, 12), > + }, > + [MT8173_POWER_DOMAIN_MM] = { > + .sta_mask = PWR_STATUS_DISP, > + .ctl_offs = SPM_DIS_PWR_CON, > + .sram_pdn_bits = GENMASK(11, 8), > + .sram_pdn_ack_bits = GENMASK(12, 12), > + .bp_infracfg = { > + .bus_prot_reg_update = true, > + .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 | > + MT8173_TOP_AXI_PROT_EN_MM_M1, > + }, > + }, > + [MT8173_POWER_DOMAIN_VENC_LT] = { > + .sta_mask = PWR_STATUS_VENC_LT, > + .ctl_offs = SPM_VEN2_PWR_CON, > + .sram_pdn_bits = GENMASK(11, 8), > + .sram_pdn_ack_bits = GENMASK(15, 12), > + }, > + [MT8173_POWER_DOMAIN_AUDIO] = { > + .sta_mask = PWR_STATUS_AUDIO, > + .ctl_offs = SPM_AUDIO_PWR_CON, > + .sram_pdn_bits = GENMASK(11, 8), > + .sram_pdn_ack_bits = GENMASK(15, 12), > + }, > + [MT8173_POWER_DOMAIN_USB] = { > + .sta_mask = PWR_STATUS_USB, > + .ctl_offs = SPM_USB_PWR_CON, > + .sram_pdn_bits = GENMASK(11, 8), > + .sram_pdn_ack_bits = GENMASK(15, 12), > + .caps = MTK_SCPD_ACTIVE_WAKEUP, > + }, > + [MT8173_POWER_DOMAIN_MFG_ASYNC] = { > + .sta_mask = PWR_STATUS_MFG_ASYNC, > + .ctl_offs = SPM_MFG_ASYNC_PWR_CON, > + .sram_pdn_bits = GENMASK(11, 8), > + .sram_pdn_ack_bits = 0, > + }, > + [MT8173_POWER_DOMAIN_MFG_2D] = { > + .sta_mask = PWR_STATUS_MFG_2D, > + .ctl_offs = SPM_MFG_2D_PWR_CON, > + .sram_pdn_bits = GENMASK(11, 8), > + .sram_pdn_ack_bits = GENMASK(13, 12), > + }, > + [MT8173_POWER_DOMAIN_MFG] = { > + .sta_mask = PWR_STATUS_MFG, > + .ctl_offs = SPM_MFG_PWR_CON, > + .sram_pdn_bits = GENMASK(13, 8), > + .sram_pdn_ack_bits = GENMASK(21, 16), > + .bp_infracfg = { > + .bus_prot_reg_update = true, > + .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S | > + MT8173_TOP_AXI_PROT_EN_MFG_M0 | > + MT8173_TOP_AXI_PROT_EN_MFG_M1 | > + MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT, > + }, > + }, > +}; > + > +static const struct scpsys_soc_data mt8173_scpsys_data = { > + .domains = scpsys_domain_data_mt8173, > + .num_domains = ARRAY_SIZE(scpsys_domain_data_mt8173), > + .pwr_sta_offs = SPM_PWR_STATUS, > + .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND, > +}; > + > +static const struct of_device_id scpsys_of_match[] = { > + { > + .compatible = "mediatek,mt8173-power-controller", > + .data = &mt8173_scpsys_data, > + }, > + { } > +}; > + > +static int scpsys_probe(struct platform_device *pdev) > +{ > + struct device *dev = &pdev->dev; > + struct device_node *np = dev->of_node; > + const struct scpsys_soc_data *soc; > + struct device_node *node; > + struct scpsys *scpsys; > + struct resource *res; > + int ret; > + > + soc = of_device_get_match_data(&pdev->dev); > + if (!soc) { > + dev_err(&pdev->dev, "no power controller data\n"); > + return -EINVAL; > + } > + > + scpsys = devm_kzalloc(dev, struct_size(scpsys, domains, soc->num_domains), GFP_KERNEL); > + if (!scpsys) > + return -ENOMEM; > + > + scpsys->dev = dev; > + scpsys->soc_data = soc; > + > + scpsys->pd_data.domains = scpsys->domains; > + scpsys->pd_data.num_domains = soc->num_domains; > + > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + scpsys->base = devm_ioremap_resource(dev, res); > + if (IS_ERR(scpsys->base)) > + return -ENODEV; > + > + ret = -ENODEV; > + for_each_available_child_of_node(np, node) { > + ret = scpsys_add_one_domain(scpsys, node); > + if (ret) { > + dev_err(dev, "failed to handle node %pOFN: %d\n", node, ret); > + of_node_put(node); > + goto err_cleanup_domains; > + } > + > + ret = scpsys_add_subdomain(scpsys, node); > + if (ret) { > + dev_err(dev, "failed to add subdomain node %pOFn: %d\n", node, ret); > + of_node_put(node); > + goto err_cleanup_domains; > + } > + } > + > + if (ret) { > + dev_dbg(dev, "no power domains present\n"); > + return ret; > + } > + > + ret = of_genpd_add_provider_onecell(np, &scpsys->pd_data); > + if (ret) { > + dev_err(dev, "failed to add provider: %d\n", ret); > + goto err_cleanup_domains; > + } > + > + return 0; > + > +err_cleanup_domains: > + scpsys_domain_cleanup(scpsys); > + return ret; > +} > + > +static struct platform_driver scpsys_pm_domain_driver = { > + .probe = scpsys_probe, > + .driver = { > + .name = "mtk-power-controller", > + .suppress_bind_attrs = true, > + .of_match_table = scpsys_of_match, > + }, > +}; > +builtin_platform_driver(scpsys_pm_domain_driver); _______________________________________________ Linux-mediatek mailing list Linux-mediatek@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-mediatek From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.4 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH, MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,UNPARSEABLE_RELAY, URIBL_BLOCKED,USER_AGENT_SANE_2 autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 56E21C4363D for ; Fri, 25 Sep 2020 10:27:11 +0000 (UTC) Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id DAA9D221EB for ; Fri, 25 Sep 2020 10:27:10 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="EbBnNbK4"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="N8wJCbgX" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org DAA9D221EB Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:Cc:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Date:To:From: Subject:Message-ID:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=BfXRjSiaflxkR+3hWGHAEaMr/KITRQBwgeNfDqK2gmY=; b=EbBnNbK44R/xxuHMfHzHO5+bk E6sGcEcloGsuk1iSt9oUxn4sQvHLMzXzy0RpnW/59zqhHx+G7RH40KLKNxFIMUwgmQ+KXTHqRIrFY 0tUrFEkqmWKEY/X+2+Hkp4apXFiLgnQaHdI3secUZGUkBDZUq1J/erV2/xAW/yp6H3tuRl+198UA7 lbFZbomsBwLy4frIRrzs5GbyyTzT2R9YLOS8/FiQazO9lObZ4+WJf2IgDiEfQZMEOyL5DLMnux3ul bRyaCBhZfuuvanpvu32aotwNbqc5kZRqbjaDL7eLb+6JsHwYRqf3enoHKPGBVDIojf/3sfvj/d82/ y2x70V1Iw==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1kLkv2-0005b6-Bw; Fri, 25 Sep 2020 10:25:36 +0000 Received: from mailgw02.mediatek.com ([216.200.240.185]) by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1kLkux-0005a9-Ip; Fri, 25 Sep 2020 10:25:33 +0000 X-UUID: cd54fcda55e44bac996c6519d506c8c7-20200925 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Transfer-Encoding:MIME-Version:Content-Type:References:In-Reply-To:Date:CC:To:From:Subject:Message-ID; bh=furd6J9lKYw7rEQJct0IXtstQo7k4wrpljtEUJ2R3XM=; b=N8wJCbgXUmJTijCMnBU1JdtQUxzkc8/F7ijdUUzpmXT+UInL5DGxgRg/K6Zo235bcYtcKD51h3aPta8hspDOLVgtQylyyWtuCRjHSdXkgjIxxM95GM+FJ3iPyZOMJ4djGyc+IyPVcLLb8vknBZuOUBbQjU/X0BFlCWc3lNotLIM=; X-UUID: cd54fcda55e44bac996c6519d506c8c7-20200925 Received: from mtkcas66.mediatek.inc [(172.29.193.44)] by mailgw02.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 815120003; Fri, 25 Sep 2020 02:25:25 -0800 Received: from mtkmbs05n2.mediatek.inc (172.21.101.140) by MTKMBS62N2.mediatek.inc (172.29.193.42) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Fri, 25 Sep 2020 03:25:23 -0700 Received: from MTKCAS06.mediatek.inc (172.21.101.30) by mtkmbs05n2.mediatek.inc (172.21.101.140) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Fri, 25 Sep 2020 18:25:21 +0800 Received: from [172.21.77.4] (172.21.77.4) by MTKCAS06.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Fri, 25 Sep 2020 18:25:21 +0800 Message-ID: <1601029522.1346.53.camel@mtksdaap41> Subject: Re: [PATCH 02/12] soc: mediatek: Add MediaTek SCPSYS power domains From: Weiyi Lu To: Enric Balletbo i Serra Date: Fri, 25 Sep 2020 18:25:22 +0800 In-Reply-To: <20200910172826.3074357-3-enric.balletbo@collabora.com> References: <20200910172826.3074357-1-enric.balletbo@collabora.com> <20200910172826.3074357-3-enric.balletbo@collabora.com> X-Mailer: Evolution 3.10.4-0ubuntu2 MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200925_062531_877383_7D18C8FF X-CRM114-Status: GOOD ( 28.18 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: drinkcat@chromium.org, linux-kernel@vger.kernel.org, fparent@baylibre.com, Matthias Brugger , linux-mediatek@lists.infradead.org, hsinyi@chromium.org, matthias.bgg@gmail.com, Collabora Kernel ML , linux-arm-kernel@lists.infradead.org Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org On Thu, 2020-09-10 at 19:28 +0200, Enric Balletbo i Serra wrote: > The System Control Processor System (SCPSYS) has several power management > related tasks in the system. This driver implements support to handle > the different power domains supported in order to meet high performance > and low power requirements. > > Co-developed-by: Matthias Brugger > Signed-off-by: Matthias Brugger > Signed-off-by: Enric Balletbo i Serra > --- > > drivers/soc/mediatek/Kconfig | 13 + > drivers/soc/mediatek/Makefile | 1 + > drivers/soc/mediatek/mtk-pm-domains.c | 626 ++++++++++++++++++++++++++ > 3 files changed, 640 insertions(+) > create mode 100644 drivers/soc/mediatek/mtk-pm-domains.c > > diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig > index 59a56cd790ec..68d800f9e4a5 100644 > --- a/drivers/soc/mediatek/Kconfig > +++ b/drivers/soc/mediatek/Kconfig > @@ -44,6 +44,19 @@ config MTK_SCPSYS > Say yes here to add support for the MediaTek SCPSYS power domain > driver. > > +config MTK_SCPSYS_PM_DOMAINS > + bool "MediaTek SCPSYS generic power domain" > + default ARCH_MEDIATEK > + depends on PM > + depends on MTK_INFRACFG > + select PM_GENERIC_DOMAINS > + select REGMAP > + help > + Say y here to enable power domain support. > + In order to meet high performance and low power requirements, the System > + Control Processor System (SCPSYS) has several power management related > + tasks in the system. > + > config MTK_MMSYS > bool "MediaTek MMSYS Support" > default ARCH_MEDIATEK > diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile > index 01f9f873634a..1e60fb4f89d4 100644 > --- a/drivers/soc/mediatek/Makefile > +++ b/drivers/soc/mediatek/Makefile > @@ -3,4 +3,5 @@ obj-$(CONFIG_MTK_CMDQ) += mtk-cmdq-helper.o > obj-$(CONFIG_MTK_INFRACFG) += mtk-infracfg.o > obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o > obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o > +obj-$(CONFIG_MTK_SCPSYS_PM_DOMAINS) += mtk-pm-domains.o > obj-$(CONFIG_MTK_MMSYS) += mtk-mmsys.o > diff --git a/drivers/soc/mediatek/mtk-pm-domains.c b/drivers/soc/mediatek/mtk-pm-domains.c > new file mode 100644 > index 000000000000..db631dbaf2e3 > --- /dev/null > +++ b/drivers/soc/mediatek/mtk-pm-domains.c > @@ -0,0 +1,626 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * Copyright (c) 2020 Collabora Ltd. > + */ > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > + > +#define MTK_POLL_DELAY_US 10 > +#define MTK_POLL_TIMEOUT USEC_PER_SEC > + > +#define MTK_SCPD_ACTIVE_WAKEUP BIT(0) > +#define MTK_SCPD_FWAIT_SRAM BIT(1) > +#define MTK_SCPD_CAPS(_scpd, _x) ((_scpd)->data->caps & (_x)) > + > +#define SPM_VDE_PWR_CON 0x0210 > +#define SPM_MFG_PWR_CON 0x0214 > +#define SPM_VEN_PWR_CON 0x0230 > +#define SPM_ISP_PWR_CON 0x0238 > +#define SPM_DIS_PWR_CON 0x023c > +#define SPM_VEN2_PWR_CON 0x0298 > +#define SPM_AUDIO_PWR_CON 0x029c > +#define SPM_MFG_2D_PWR_CON 0x02c0 > +#define SPM_MFG_ASYNC_PWR_CON 0x02c4 > +#define SPM_USB_PWR_CON 0x02cc > + If me, I'd choose to write directly into the data of each SoC now because it's inconsistent on most MediatTek chips. > +#define SPM_PWR_STATUS 0x060c > +#define SPM_PWR_STATUS_2ND 0x0610 > + > +#define PWR_RST_B_BIT BIT(0) > +#define PWR_ISO_BIT BIT(1) > +#define PWR_ON_BIT BIT(2) > +#define PWR_ON_2ND_BIT BIT(3) > +#define PWR_CLK_DIS_BIT BIT(4) > + > +#define PWR_STATUS_DISP BIT(3) > +#define PWR_STATUS_MFG BIT(4) > +#define PWR_STATUS_ISP BIT(5) > +#define PWR_STATUS_VDEC BIT(7) > +#define PWR_STATUS_VENC_LT BIT(20) > +#define PWR_STATUS_VENC BIT(21) > +#define PWR_STATUS_MFG_2D BIT(22) > +#define PWR_STATUS_MFG_ASYNC BIT(23) > +#define PWR_STATUS_AUDIO BIT(24) > +#define PWR_STATUS_USB BIT(25) > + same here for the status bits. > +struct scpsys_bus_prot_data { > + u32 bus_prot_mask; > + bool bus_prot_reg_update; > +}; > + > +/** > + * struct scpsys_domain_data - scp domain data for power on/off flow > + * @sta_mask: The mask for power on/off status bit. > + * @ctl_offs: The offset for main power control register. > + * @sram_pdn_bits: The mask for sram power control bits. > + * @sram_pdn_ack_bits: The mask for sram power control acked bits. > + * @caps: The flag for active wake-up action. > + * @bp_infracfg: bus protection for infracfg subsystem > + */ > +struct scpsys_domain_data { > + u32 sta_mask; > + int ctl_offs; > + u32 sram_pdn_bits; > + u32 sram_pdn_ack_bits; > + u8 caps; > + const struct scpsys_bus_prot_data bp_infracfg; > +}; > + > +struct scpsys_domain { > + struct generic_pm_domain genpd; > + const struct scpsys_domain_data *data; > + struct scpsys *scpsys; > + int num_clks; > + struct clk_bulk_data *clks; > + struct regmap *infracfg; Could we move struct regmap *infracfg; back to struct scpsys? It seems we need to set this property many times under each power domain sub node in device tree? > +}; > + > +struct scpsys_soc_data { > + const struct scpsys_domain_data *domains; > + int num_domains; > + int pwr_sta_offs; > + int pwr_sta2nd_offs; > +}; > + > +struct scpsys { > + struct device *dev; > + void __iomem *base; > + const struct scpsys_soc_data *soc_data; > + struct genpd_onecell_data pd_data; > + struct generic_pm_domain *domains[]; > +}; > + > +#define to_scpsys_domain(gpd) container_of(gpd, struct scpsys_domain, genpd) > + > +static int scpsys_domain_is_on(struct scpsys_domain *pd) > +{ > + struct scpsys *scpsys = pd->scpsys; > + > + u32 status = readl(scpsys->base + scpsys->soc_data->pwr_sta_offs) & pd->data->sta_mask; > + u32 status2 = readl(scpsys->base + scpsys->soc_data->pwr_sta2nd_offs) & pd->data->sta_mask; > + > + /* > + * A domain is on when both status bits are set. If only one is set > + * return an error. This happens while powering up a domain > + */ > + > + if (status && status2) > + return true; > + if (!status && !status2) > + return false; > + > + return -EINVAL; > +} > + > +static int scpsys_sram_enable(struct scpsys_domain *pd, void __iomem *ctl_addr) > +{ > + u32 pdn_ack = pd->data->sram_pdn_ack_bits; > + u32 val; > + int tmp; > + int ret; > + > + val = readl(ctl_addr); > + val &= ~pd->data->sram_pdn_bits; > + writel(val, ctl_addr); > + > + /* Either wait until SRAM_PDN_ACK all 1 or 0 */ > + ret = readl_poll_timeout(ctl_addr, tmp, (tmp & pdn_ack) == 0, MTK_POLL_DELAY_US, > + MTK_POLL_TIMEOUT); > + if (ret < 0) > + return ret; > + > + return 0; > +} > + > +static int scpsys_sram_disable(struct scpsys_domain *pd, void __iomem *ctl_addr) > +{ > + u32 pdn_ack = pd->data->sram_pdn_ack_bits; > + u32 val; > + int tmp; > + > + val = readl(ctl_addr); > + val |= pd->data->sram_pdn_bits; > + writel(val, ctl_addr); > + > + /* Either wait until SRAM_PDN_ACK all 1 or 0 */ > + return readl_poll_timeout(ctl_addr, tmp, (tmp & pdn_ack) == pdn_ack, MTK_POLL_DELAY_US, > + MTK_POLL_TIMEOUT); > +} > + > +static int scpsys_bus_protect_enable(struct scpsys_domain *pd) > +{ > + const struct scpsys_bus_prot_data *bp_data = &pd->data->bp_infracfg; > + > + if (!bp_data->bus_prot_mask) > + return 0; > + > + return mtk_infracfg_set_bus_protection(pd->infracfg, bp_data->bus_prot_mask, > + bp_data->bus_prot_reg_update); > +} > + > +static int scpsys_bus_protect_disable(struct scpsys_domain *pd) > +{ > + const struct scpsys_bus_prot_data *bp_data = &pd->data->bp_infracfg; > + > + if (!bp_data->bus_prot_mask) > + return 0; > + > + return mtk_infracfg_clear_bus_protection(pd->infracfg, bp_data->bus_prot_mask, > + bp_data->bus_prot_reg_update); > +} > + > +static int scpsys_power_on(struct generic_pm_domain *genpd) > +{ > + struct scpsys_domain *pd = container_of(genpd, struct scpsys_domain, genpd); > + struct scpsys *scpsys = pd->scpsys; > + void __iomem *ctl_addr = scpsys->base + pd->data->ctl_offs; > + int ret, tmp; > + u32 val; > + > + ret = clk_bulk_enable(pd->num_clks, pd->clks); > + if (ret) > + return ret; > + > + /* subsys power on */ > + val = readl(ctl_addr); > + val |= PWR_ON_BIT; > + writel(val, ctl_addr); > + val |= PWR_ON_2ND_BIT; > + writel(val, ctl_addr); > + > + /* wait until PWR_ACK = 1 */ > + ret = readx_poll_timeout(scpsys_domain_is_on, pd, tmp, tmp > 0, MTK_POLL_DELAY_US, > + MTK_POLL_TIMEOUT); > + if (ret < 0) > + goto err_pwr_ack; > + > + val &= ~PWR_CLK_DIS_BIT; > + writel(val, ctl_addr); > + > + val &= ~PWR_ISO_BIT; > + writel(val, ctl_addr); > + > + val |= PWR_RST_B_BIT; > + writel(val, ctl_addr); > + > + ret = scpsys_sram_enable(pd, ctl_addr); > + if (ret < 0) > + goto err_pwr_ack; > + > + ret = scpsys_bus_protect_disable(pd); > + if (ret < 0) > + goto err_pwr_ack; > + > + return 0; > + > +err_pwr_ack: > + clk_bulk_disable(pd->num_clks, pd->clks); > + dev_err(scpsys->dev, "Failed to power on domain %s\n", genpd->name); > + > + return ret; > +} > + > +static int scpsys_power_off(struct generic_pm_domain *genpd) > +{ > + struct scpsys_domain *pd = container_of(genpd, struct scpsys_domain, genpd); > + struct scpsys *scpsys = pd->scpsys; > + void __iomem *ctl_addr = scpsys->base + pd->data->ctl_offs; > + int ret, tmp; > + u32 val; > + > + ret = scpsys_bus_protect_enable(pd); > + if (ret < 0) > + return ret; > + > + ret = scpsys_sram_disable(pd, ctl_addr); > + if (ret < 0) > + return ret; > + > + /* subsys power off */ > + val = readl(ctl_addr); > + val |= PWR_ISO_BIT; > + writel(val, ctl_addr); > + > + val &= ~PWR_RST_B_BIT; > + writel(val, ctl_addr); > + > + val |= PWR_CLK_DIS_BIT; > + writel(val, ctl_addr); > + > + val &= ~PWR_ON_BIT; > + writel(val, ctl_addr); > + > + val &= ~PWR_ON_2ND_BIT; > + writel(val, ctl_addr); > + > + /* wait until PWR_ACK = 0 */ > + ret = readx_poll_timeout(scpsys_domain_is_on, pd, tmp, tmp == 0, MTK_POLL_DELAY_US, > + MTK_POLL_TIMEOUT); > + if (ret < 0) > + return ret; > + > + clk_bulk_disable(pd->num_clks, pd->clks); > + > + return 0; > +} > + > +static int scpsys_add_one_domain(struct scpsys *scpsys, struct device_node *node) > +{ > + const struct scpsys_domain_data *domain_data; > + struct scpsys_domain *pd; > + int i, ret; > + u32 id; > + > + ret = of_property_read_u32(node, "reg", &id); > + if (ret) { > + dev_err(scpsys->dev, "%pOFn: failed to retrieve domain id from reg: %d\n", node, > + ret); > + return -EINVAL; > + } > + > + if (id >= scpsys->soc_data->num_domains) { > + dev_err(scpsys->dev, "%pOFn: invalid domain id %d\n", node, id); > + return -EINVAL; > + } > + > + domain_data = &scpsys->soc_data->domains[id]; > + if (!domain_data) { > + dev_err(scpsys->dev, "%pOFn: undefined domain id %d\n", node, id); > + return -EINVAL; > + } > + > + pd = devm_kzalloc(scpsys->dev, sizeof(*pd), GFP_KERNEL); > + if (!pd) > + return -ENOMEM; > + > + pd->data = domain_data; > + pd->scpsys = scpsys; > + > + pd->infracfg = syscon_regmap_lookup_by_phandle(node, "mediatek,infracfg"); > + if (IS_ERR(pd->infracfg)) > + pd->infracfg = NULL; > + > + pd->num_clks = of_clk_get_parent_count(node); > + if (pd->num_clks > 0) { > + pd->clks = devm_kcalloc(scpsys->dev, pd->num_clks, sizeof(*pd->clks), GFP_KERNEL); > + if (!pd->clks) > + return -ENOMEM; > + } else { > + pd->num_clks = 0; > + } > + > + for (i = 0; i < pd->num_clks; i++) { > + pd->clks[i].clk = of_clk_get(node, i); Is it possible to have a better way that we could use of_clk_bulk_get()? > + if (IS_ERR(pd->clks[i].clk)) { > + ret = PTR_ERR(pd->clks[i].clk); > + dev_err(scpsys->dev, "%pOFn: failed to get clk at index %d: %d\n", node, i, > + ret); > + return ret; > + } > + } > + > + ret = clk_bulk_prepare(pd->num_clks, pd->clks); > + if (ret) > + goto err_put_clocks; > + > + /* > + * Initially turn on all domains to make the domains usable > + * with !CONFIG_PM and to get the hardware in sync with the > + * software. The unused domains will be switched off during > + * late_init time. > + */ > + ret = scpsys_power_on(&pd->genpd); > + if (ret < 0) { > + dev_err(scpsys->dev, "failed to power on domain %pOFN with error %d\n", node, ret); > + goto err_unprepare_clocks; > + } > + > + pd->genpd.name = node->name; > + pd->genpd.power_off = scpsys_power_off; > + pd->genpd.power_on = scpsys_power_on; > + > + pm_genpd_init(&pd->genpd, NULL, false); > + > + scpsys->domains[id] = &pd->genpd; > + return 0; > + > +err_unprepare_clocks: > + clk_bulk_unprepare(pd->num_clks, pd->clks); > +err_put_clocks: > + clk_bulk_put(pd->num_clks, pd->clks); > + devm_kfree(scpsys->dev, pd->clks); > + pd->num_clks = 0; > + return ret; > +} > + > +static int scpsys_add_subdomain(struct scpsys *scpsys, struct device_node *parent) > +{ > + struct device_node *child; > + struct generic_pm_domain *child_pd, *parent_pd; > + int ret; > + > + for_each_child_of_node(parent, child) { > + u32 id; > + > + ret = of_property_read_u32(parent, "reg", &id); > + if (ret) { > + dev_err(scpsys->dev, "%pOFn: failed to get parent domain id: %d\n", child, > + ret); > + goto err_put_node; > + } > + parent_pd = scpsys->pd_data.domains[id]; > + nit. Could we move parent outside(in front of) the loop? > + ret = scpsys_add_one_domain(scpsys, child); > + if (ret) { > + dev_err(scpsys->dev, "error adding power domain for %pOFn: %d\n", child, > + ret); > + goto err_put_node; > + } > + > + ret = of_property_read_u32(child, "reg", &id); > + if (ret) { > + dev_err(scpsys->dev, "%pOFn: failed to get child domain id: %d\n", child, > + ret); > + goto err_put_node; > + } > + child_pd = scpsys->pd_data.domains[id]; > + > + ret = pm_genpd_add_subdomain(parent_pd, child_pd); > + if (ret) { > + dev_err(scpsys->dev, "failed to add %s subdomain to parent %s\n", > + child_pd->name, parent_pd->name); > + goto err_put_node; > + } else { > + dev_dbg(scpsys->dev, "%s add subdomain: %s\n", parent_pd->name, > + child_pd->name); > + } > + > + /* recursive call to add all subdomains */ > + ret = scpsys_add_subdomain(scpsys, child); > + if (ret) > + goto err_put_node; > + } > + > + return 0; > + > +err_put_node: > + of_node_put(child); > + return ret; > +} > + > +static void scpsys_remove_one_domain(struct scpsys_domain *pd) > +{ > + int ret; > + > + /* > + * We're in the error cleanup already, so we only complain, > + * but won't emit another error on top of the original one. > + */ > + ret = pm_genpd_remove(&pd->genpd); > + if (ret < 0) > + dev_err(pd->scpsys->dev, > + "failed to remove domain '%s' : %d - state may be inconsistent\n", > + pd->genpd.name, ret); > + > + scpsys_power_off(&pd->genpd); > + > + clk_bulk_unprepare(pd->num_clks, pd->clks); > + clk_bulk_put(pd->num_clks, pd->clks); > + pd->num_clks = 0; > +} > + > +static void scpsys_domain_cleanup(struct scpsys *scpsys) > +{ > + struct generic_pm_domain *genpd; > + struct scpsys_domain *pd; > + int i; > + > + for (i = scpsys->pd_data.num_domains - 1; i >= 0; i--) { > + genpd = scpsys->pd_data.domains[i]; > + if (genpd) { > + pd = to_scpsys_domain(genpd); > + scpsys_remove_one_domain(pd); > + } > + } > +} > + > +/* > + * MT8173 power domain support > + */ > + > +static const struct scpsys_domain_data scpsys_domain_data_mt8173[] = { > + [MT8173_POWER_DOMAIN_VDEC] = { > + .sta_mask = PWR_STATUS_VDEC, > + .ctl_offs = SPM_VDE_PWR_CON, > + .sram_pdn_bits = GENMASK(11, 8), > + .sram_pdn_ack_bits = GENMASK(12, 12), > + }, > + [MT8173_POWER_DOMAIN_VENC] = { > + .sta_mask = PWR_STATUS_VENC, > + .ctl_offs = SPM_VEN_PWR_CON, > + .sram_pdn_bits = GENMASK(11, 8), > + .sram_pdn_ack_bits = GENMASK(15, 12), > + }, > + [MT8173_POWER_DOMAIN_ISP] = { > + .sta_mask = PWR_STATUS_ISP, > + .ctl_offs = SPM_ISP_PWR_CON, > + .sram_pdn_bits = GENMASK(11, 8), > + .sram_pdn_ack_bits = GENMASK(13, 12), > + }, > + [MT8173_POWER_DOMAIN_MM] = { > + .sta_mask = PWR_STATUS_DISP, > + .ctl_offs = SPM_DIS_PWR_CON, > + .sram_pdn_bits = GENMASK(11, 8), > + .sram_pdn_ack_bits = GENMASK(12, 12), > + .bp_infracfg = { > + .bus_prot_reg_update = true, > + .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 | > + MT8173_TOP_AXI_PROT_EN_MM_M1, > + }, > + }, > + [MT8173_POWER_DOMAIN_VENC_LT] = { > + .sta_mask = PWR_STATUS_VENC_LT, > + .ctl_offs = SPM_VEN2_PWR_CON, > + .sram_pdn_bits = GENMASK(11, 8), > + .sram_pdn_ack_bits = GENMASK(15, 12), > + }, > + [MT8173_POWER_DOMAIN_AUDIO] = { > + .sta_mask = PWR_STATUS_AUDIO, > + .ctl_offs = SPM_AUDIO_PWR_CON, > + .sram_pdn_bits = GENMASK(11, 8), > + .sram_pdn_ack_bits = GENMASK(15, 12), > + }, > + [MT8173_POWER_DOMAIN_USB] = { > + .sta_mask = PWR_STATUS_USB, > + .ctl_offs = SPM_USB_PWR_CON, > + .sram_pdn_bits = GENMASK(11, 8), > + .sram_pdn_ack_bits = GENMASK(15, 12), > + .caps = MTK_SCPD_ACTIVE_WAKEUP, > + }, > + [MT8173_POWER_DOMAIN_MFG_ASYNC] = { > + .sta_mask = PWR_STATUS_MFG_ASYNC, > + .ctl_offs = SPM_MFG_ASYNC_PWR_CON, > + .sram_pdn_bits = GENMASK(11, 8), > + .sram_pdn_ack_bits = 0, > + }, > + [MT8173_POWER_DOMAIN_MFG_2D] = { > + .sta_mask = PWR_STATUS_MFG_2D, > + .ctl_offs = SPM_MFG_2D_PWR_CON, > + .sram_pdn_bits = GENMASK(11, 8), > + .sram_pdn_ack_bits = GENMASK(13, 12), > + }, > + [MT8173_POWER_DOMAIN_MFG] = { > + .sta_mask = PWR_STATUS_MFG, > + .ctl_offs = SPM_MFG_PWR_CON, > + .sram_pdn_bits = GENMASK(13, 8), > + .sram_pdn_ack_bits = GENMASK(21, 16), > + .bp_infracfg = { > + .bus_prot_reg_update = true, > + .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S | > + MT8173_TOP_AXI_PROT_EN_MFG_M0 | > + MT8173_TOP_AXI_PROT_EN_MFG_M1 | > + MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT, > + }, > + }, > +}; > + > +static const struct scpsys_soc_data mt8173_scpsys_data = { > + .domains = scpsys_domain_data_mt8173, > + .num_domains = ARRAY_SIZE(scpsys_domain_data_mt8173), > + .pwr_sta_offs = SPM_PWR_STATUS, > + .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND, > +}; > + > +static const struct of_device_id scpsys_of_match[] = { > + { > + .compatible = "mediatek,mt8173-power-controller", > + .data = &mt8173_scpsys_data, > + }, > + { } > +}; > + > +static int scpsys_probe(struct platform_device *pdev) > +{ > + struct device *dev = &pdev->dev; > + struct device_node *np = dev->of_node; > + const struct scpsys_soc_data *soc; > + struct device_node *node; > + struct scpsys *scpsys; > + struct resource *res; > + int ret; > + > + soc = of_device_get_match_data(&pdev->dev); > + if (!soc) { > + dev_err(&pdev->dev, "no power controller data\n"); > + return -EINVAL; > + } > + > + scpsys = devm_kzalloc(dev, struct_size(scpsys, domains, soc->num_domains), GFP_KERNEL); > + if (!scpsys) > + return -ENOMEM; > + > + scpsys->dev = dev; > + scpsys->soc_data = soc; > + > + scpsys->pd_data.domains = scpsys->domains; > + scpsys->pd_data.num_domains = soc->num_domains; > + > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + scpsys->base = devm_ioremap_resource(dev, res); > + if (IS_ERR(scpsys->base)) > + return -ENODEV; > + > + ret = -ENODEV; > + for_each_available_child_of_node(np, node) { > + ret = scpsys_add_one_domain(scpsys, node); > + if (ret) { > + dev_err(dev, "failed to handle node %pOFN: %d\n", node, ret); > + of_node_put(node); > + goto err_cleanup_domains; > + } > + > + ret = scpsys_add_subdomain(scpsys, node); > + if (ret) { > + dev_err(dev, "failed to add subdomain node %pOFn: %d\n", node, ret); > + of_node_put(node); > + goto err_cleanup_domains; > + } > + } > + > + if (ret) { > + dev_dbg(dev, "no power domains present\n"); > + return ret; > + } > + > + ret = of_genpd_add_provider_onecell(np, &scpsys->pd_data); > + if (ret) { > + dev_err(dev, "failed to add provider: %d\n", ret); > + goto err_cleanup_domains; > + } > + > + return 0; > + > +err_cleanup_domains: > + scpsys_domain_cleanup(scpsys); > + return ret; > +} > + > +static struct platform_driver scpsys_pm_domain_driver = { > + .probe = scpsys_probe, > + .driver = { > + .name = "mtk-power-controller", > + .suppress_bind_attrs = true, > + .of_match_table = scpsys_of_match, > + }, > +}; > +builtin_platform_driver(scpsys_pm_domain_driver); _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-11.3 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH, MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,UNPARSEABLE_RELAY, URIBL_BLOCKED,USER_AGENT_SANE_2 autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 36B09C4363D for ; Fri, 25 Sep 2020 10:25:37 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id BF417206C9 for ; Fri, 25 Sep 2020 10:25:36 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="N8wJCbgX" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728011AbgIYKZf (ORCPT ); Fri, 25 Sep 2020 06:25:35 -0400 Received: from mailgw01.mediatek.com ([210.61.82.183]:37652 "EHLO mailgw01.mediatek.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1727132AbgIYKZf (ORCPT ); Fri, 25 Sep 2020 06:25:35 -0400 X-UUID: 8e940b4733d54b73b81cd9dd791b9a9b-20200925 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Transfer-Encoding:MIME-Version:Content-Type:References:In-Reply-To:Date:CC:To:From:Subject:Message-ID; bh=furd6J9lKYw7rEQJct0IXtstQo7k4wrpljtEUJ2R3XM=; b=N8wJCbgXUmJTijCMnBU1JdtQUxzkc8/F7ijdUUzpmXT+UInL5DGxgRg/K6Zo235bcYtcKD51h3aPta8hspDOLVgtQylyyWtuCRjHSdXkgjIxxM95GM+FJ3iPyZOMJ4djGyc+IyPVcLLb8vknBZuOUBbQjU/X0BFlCWc3lNotLIM=; X-UUID: 8e940b4733d54b73b81cd9dd791b9a9b-20200925 Received: from mtkcas11.mediatek.inc [(172.21.101.40)] by mailgw01.mediatek.com (envelope-from ) (Cellopoint E-mail Firewall v4.1.14 Build 0819 with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 1970134338; Fri, 25 Sep 2020 18:25:23 +0800 Received: from MTKCAS06.mediatek.inc (172.21.101.30) by mtkmbs05n2.mediatek.inc (172.21.101.140) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Fri, 25 Sep 2020 18:25:21 +0800 Received: from [172.21.77.4] (172.21.77.4) by MTKCAS06.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Fri, 25 Sep 2020 18:25:21 +0800 Message-ID: <1601029522.1346.53.camel@mtksdaap41> Subject: Re: [PATCH 02/12] soc: mediatek: Add MediaTek SCPSYS power domains From: Weiyi Lu To: Enric Balletbo i Serra CC: , Collabora Kernel ML , , , , , Matthias Brugger , , Date: Fri, 25 Sep 2020 18:25:22 +0800 In-Reply-To: <20200910172826.3074357-3-enric.balletbo@collabora.com> References: <20200910172826.3074357-1-enric.balletbo@collabora.com> <20200910172826.3074357-3-enric.balletbo@collabora.com> Content-Type: text/plain; charset="UTF-8" X-Mailer: Evolution 3.10.4-0ubuntu2 MIME-Version: 1.0 X-MTK: N Content-Transfer-Encoding: base64 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org T24gVGh1LCAyMDIwLTA5LTEwIGF0IDE5OjI4ICswMjAwLCBFbnJpYyBCYWxsZXRibyBpIFNlcnJh IHdyb3RlOg0KPiBUaGUgU3lzdGVtIENvbnRyb2wgUHJvY2Vzc29yIFN5c3RlbSAoU0NQU1lTKSBo YXMgc2V2ZXJhbCBwb3dlciBtYW5hZ2VtZW50DQo+IHJlbGF0ZWQgdGFza3MgaW4gdGhlIHN5c3Rl bS4gVGhpcyBkcml2ZXIgaW1wbGVtZW50cyBzdXBwb3J0IHRvIGhhbmRsZQ0KPiB0aGUgZGlmZmVy ZW50IHBvd2VyIGRvbWFpbnMgc3VwcG9ydGVkIGluIG9yZGVyIHRvIG1lZXQgaGlnaCBwZXJmb3Jt YW5jZQ0KPiBhbmQgbG93IHBvd2VyIHJlcXVpcmVtZW50cy4NCj4gDQo+IENvLWRldmVsb3BlZC1i eTogTWF0dGhpYXMgQnJ1Z2dlciA8bWJydWdnZXJAc3VzZS5jb20+DQo+IFNpZ25lZC1vZmYtYnk6 IE1hdHRoaWFzIEJydWdnZXIgPG1icnVnZ2VyQHN1c2UuY29tPg0KPiBTaWduZWQtb2ZmLWJ5OiBF bnJpYyBCYWxsZXRibyBpIFNlcnJhIDxlbnJpYy5iYWxsZXRib0Bjb2xsYWJvcmEuY29tPg0KPiAt LS0NCj4gDQo+ICBkcml2ZXJzL3NvYy9tZWRpYXRlay9LY29uZmlnICAgICAgICAgIHwgIDEzICsN Cj4gIGRyaXZlcnMvc29jL21lZGlhdGVrL01ha2VmaWxlICAgICAgICAgfCAgIDEgKw0KPiAgZHJp dmVycy9zb2MvbWVkaWF0ZWsvbXRrLXBtLWRvbWFpbnMuYyB8IDYyNiArKysrKysrKysrKysrKysr KysrKysrKysrKw0KPiAgMyBmaWxlcyBjaGFuZ2VkLCA2NDAgaW5zZXJ0aW9ucygrKQ0KPiAgY3Jl YXRlIG1vZGUgMTAwNjQ0IGRyaXZlcnMvc29jL21lZGlhdGVrL210ay1wbS1kb21haW5zLmMNCj4g DQo+IGRpZmYgLS1naXQgYS9kcml2ZXJzL3NvYy9tZWRpYXRlay9LY29uZmlnIGIvZHJpdmVycy9z b2MvbWVkaWF0ZWsvS2NvbmZpZw0KPiBpbmRleCA1OWE1NmNkNzkwZWMuLjY4ZDgwMGY5ZTRhNSAx MDA2NDQNCj4gLS0tIGEvZHJpdmVycy9zb2MvbWVkaWF0ZWsvS2NvbmZpZw0KPiArKysgYi9kcml2 ZXJzL3NvYy9tZWRpYXRlay9LY29uZmlnDQo+IEBAIC00NCw2ICs0NCwxOSBAQCBjb25maWcgTVRL X1NDUFNZUw0KPiAgCSAgU2F5IHllcyBoZXJlIHRvIGFkZCBzdXBwb3J0IGZvciB0aGUgTWVkaWFU ZWsgU0NQU1lTIHBvd2VyIGRvbWFpbg0KPiAgCSAgZHJpdmVyLg0KPiAgDQo+ICtjb25maWcgTVRL X1NDUFNZU19QTV9ET01BSU5TDQo+ICsJYm9vbCAiTWVkaWFUZWsgU0NQU1lTIGdlbmVyaWMgcG93 ZXIgZG9tYWluIg0KPiArCWRlZmF1bHQgQVJDSF9NRURJQVRFSw0KPiArCWRlcGVuZHMgb24gUE0N Cj4gKwlkZXBlbmRzIG9uIE1US19JTkZSQUNGRw0KPiArCXNlbGVjdCBQTV9HRU5FUklDX0RPTUFJ TlMNCj4gKwlzZWxlY3QgUkVHTUFQDQo+ICsJaGVscA0KPiArCSAgU2F5IHkgaGVyZSB0byBlbmFi bGUgcG93ZXIgZG9tYWluIHN1cHBvcnQuDQo+ICsJICBJbiBvcmRlciB0byBtZWV0IGhpZ2ggcGVy Zm9ybWFuY2UgYW5kIGxvdyBwb3dlciByZXF1aXJlbWVudHMsIHRoZSBTeXN0ZW0NCj4gKwkgIENv bnRyb2wgUHJvY2Vzc29yIFN5c3RlbSAoU0NQU1lTKSBoYXMgc2V2ZXJhbCBwb3dlciBtYW5hZ2Vt ZW50IHJlbGF0ZWQNCj4gKwkgIHRhc2tzIGluIHRoZSBzeXN0ZW0uDQo+ICsNCj4gIGNvbmZpZyBN VEtfTU1TWVMNCj4gIAlib29sICJNZWRpYVRlayBNTVNZUyBTdXBwb3J0Ig0KPiAgCWRlZmF1bHQg QVJDSF9NRURJQVRFSw0KPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9zb2MvbWVkaWF0ZWsvTWFrZWZp bGUgYi9kcml2ZXJzL3NvYy9tZWRpYXRlay9NYWtlZmlsZQ0KPiBpbmRleCAwMWY5Zjg3MzYzNGEu LjFlNjBmYjRmODlkNCAxMDA2NDQNCj4gLS0tIGEvZHJpdmVycy9zb2MvbWVkaWF0ZWsvTWFrZWZp bGUNCj4gKysrIGIvZHJpdmVycy9zb2MvbWVkaWF0ZWsvTWFrZWZpbGUNCj4gQEAgLTMsNCArMyw1 IEBAIG9iai0kKENPTkZJR19NVEtfQ01EUSkgKz0gbXRrLWNtZHEtaGVscGVyLm8NCj4gIG9iai0k KENPTkZJR19NVEtfSU5GUkFDRkcpICs9IG10ay1pbmZyYWNmZy5vDQo+ICBvYmotJChDT05GSUdf TVRLX1BNSUNfV1JBUCkgKz0gbXRrLXBtaWMtd3JhcC5vDQo+ICBvYmotJChDT05GSUdfTVRLX1ND UFNZUykgKz0gbXRrLXNjcHN5cy5vDQo+ICtvYmotJChDT05GSUdfTVRLX1NDUFNZU19QTV9ET01B SU5TKSArPSBtdGstcG0tZG9tYWlucy5vDQo+ICBvYmotJChDT05GSUdfTVRLX01NU1lTKSArPSBt dGstbW1zeXMubw0KPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9zb2MvbWVkaWF0ZWsvbXRrLXBtLWRv bWFpbnMuYyBiL2RyaXZlcnMvc29jL21lZGlhdGVrL210ay1wbS1kb21haW5zLmMNCj4gbmV3IGZp bGUgbW9kZSAxMDA2NDQNCj4gaW5kZXggMDAwMDAwMDAwMDAwLi5kYjYzMWRiYWYyZTMNCj4gLS0t IC9kZXYvbnVsbA0KPiArKysgYi9kcml2ZXJzL3NvYy9tZWRpYXRlay9tdGstcG0tZG9tYWlucy5j DQo+IEBAIC0wLDAgKzEsNjI2IEBADQo+ICsvLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogR1BM LTIuMC1vbmx5DQo+ICsvKg0KPiArICogQ29weXJpZ2h0IChjKSAyMDIwIENvbGxhYm9yYSBMdGQu DQo+ICsgKi8NCj4gKyNpbmNsdWRlIDxsaW51eC9jbGsuaD4NCj4gKyNpbmNsdWRlIDxsaW51eC9p bml0Lmg+DQo+ICsjaW5jbHVkZSA8bGludXgvaW8uaD4NCj4gKyNpbmNsdWRlIDxsaW51eC9pb3Bv bGwuaD4NCj4gKyNpbmNsdWRlIDxsaW51eC9tZmQvc3lzY29uLmg+DQo+ICsjaW5jbHVkZSA8bGlu dXgvb2ZfY2xrLmg+DQo+ICsjaW5jbHVkZSA8bGludXgvb2ZfZGV2aWNlLmg+DQo+ICsjaW5jbHVk ZSA8bGludXgvcGxhdGZvcm1fZGV2aWNlLmg+DQo+ICsjaW5jbHVkZSA8bGludXgvcG1fZG9tYWlu Lmg+DQo+ICsjaW5jbHVkZSA8bGludXgvc29jL21lZGlhdGVrL2luZnJhY2ZnLmg+DQo+ICsNCj4g KyNpbmNsdWRlIDxkdC1iaW5kaW5ncy9wb3dlci9tdDgxNzMtcG93ZXIuaD4NCj4gKw0KPiArI2Rl ZmluZSBNVEtfUE9MTF9ERUxBWV9VUyAgIDEwDQo+ICsjZGVmaW5lIE1US19QT0xMX1RJTUVPVVQg ICAgVVNFQ19QRVJfU0VDDQo+ICsNCj4gKyNkZWZpbmUgTVRLX1NDUERfQUNUSVZFX1dBS0VVUAkJ QklUKDApDQo+ICsjZGVmaW5lIE1US19TQ1BEX0ZXQUlUX1NSQU0JCUJJVCgxKQ0KPiArI2RlZmlu ZSBNVEtfU0NQRF9DQVBTKF9zY3BkLCBfeCkJKChfc2NwZCktPmRhdGEtPmNhcHMgJiAoX3gpKQ0K PiArDQo+ICsjZGVmaW5lIFNQTV9WREVfUFdSX0NPTgkJCTB4MDIxMA0KPiArI2RlZmluZSBTUE1f TUZHX1BXUl9DT04JCQkweDAyMTQNCj4gKyNkZWZpbmUgU1BNX1ZFTl9QV1JfQ09OCQkJMHgwMjMw DQo+ICsjZGVmaW5lIFNQTV9JU1BfUFdSX0NPTgkJCTB4MDIzOA0KPiArI2RlZmluZSBTUE1fRElT X1BXUl9DT04JCQkweDAyM2MNCj4gKyNkZWZpbmUgU1BNX1ZFTjJfUFdSX0NPTgkJMHgwMjk4DQo+ ICsjZGVmaW5lIFNQTV9BVURJT19QV1JfQ09OCQkweDAyOWMNCj4gKyNkZWZpbmUgU1BNX01GR18y RF9QV1JfQ09OCQkweDAyYzANCj4gKyNkZWZpbmUgU1BNX01GR19BU1lOQ19QV1JfQ09OCQkweDAy YzQNCj4gKyNkZWZpbmUgU1BNX1VTQl9QV1JfQ09OCQkJMHgwMmNjDQo+ICsNCg0KSWYgbWUsIEkn ZCBjaG9vc2UgdG8gd3JpdGUgZGlyZWN0bHkgaW50byB0aGUgZGF0YSBvZiBlYWNoIFNvQyBub3cN CmJlY2F1c2UgaXQncyBpbmNvbnNpc3RlbnQgb24gbW9zdCBNZWRpYXRUZWsgY2hpcHMuDQoNCj4g KyNkZWZpbmUgU1BNX1BXUl9TVEFUVVMJCQkweDA2MGMNCj4gKyNkZWZpbmUgU1BNX1BXUl9TVEFU VVNfMk5ECQkweDA2MTANCj4gKw0KPiArI2RlZmluZSBQV1JfUlNUX0JfQklUCQkJQklUKDApDQo+ ICsjZGVmaW5lIFBXUl9JU09fQklUCQkJQklUKDEpDQo+ICsjZGVmaW5lIFBXUl9PTl9CSVQJCQlC SVQoMikNCj4gKyNkZWZpbmUgUFdSX09OXzJORF9CSVQJCQlCSVQoMykNCj4gKyNkZWZpbmUgUFdS X0NMS19ESVNfQklUCQkJQklUKDQpDQo+ICsNCj4gKyNkZWZpbmUgUFdSX1NUQVRVU19ESVNQCQkJ QklUKDMpDQo+ICsjZGVmaW5lIFBXUl9TVEFUVVNfTUZHCQkJQklUKDQpDQo+ICsjZGVmaW5lIFBX Ul9TVEFUVVNfSVNQCQkJQklUKDUpDQo+ICsjZGVmaW5lIFBXUl9TVEFUVVNfVkRFQwkJCUJJVCg3 KQ0KPiArI2RlZmluZSBQV1JfU1RBVFVTX1ZFTkNfTFQJCUJJVCgyMCkNCj4gKyNkZWZpbmUgUFdS X1NUQVRVU19WRU5DCQkJQklUKDIxKQ0KPiArI2RlZmluZSBQV1JfU1RBVFVTX01GR18yRAkJQklU KDIyKQ0KPiArI2RlZmluZSBQV1JfU1RBVFVTX01GR19BU1lOQwkJQklUKDIzKQ0KPiArI2RlZmlu ZSBQV1JfU1RBVFVTX0FVRElPCQlCSVQoMjQpDQo+ICsjZGVmaW5lIFBXUl9TVEFUVVNfVVNCCQkJ QklUKDI1KQ0KPiArDQoNCnNhbWUgaGVyZSBmb3IgdGhlIHN0YXR1cyBiaXRzLg0KDQo+ICtzdHJ1 Y3Qgc2Nwc3lzX2J1c19wcm90X2RhdGEgew0KPiArCXUzMiBidXNfcHJvdF9tYXNrOw0KPiArCWJv b2wgYnVzX3Byb3RfcmVnX3VwZGF0ZTsNCj4gK307DQo+ICsNCj4gKy8qKg0KPiArICogc3RydWN0 IHNjcHN5c19kb21haW5fZGF0YSAtIHNjcCBkb21haW4gZGF0YSBmb3IgcG93ZXIgb24vb2ZmIGZs b3cNCj4gKyAqIEBzdGFfbWFzazogVGhlIG1hc2sgZm9yIHBvd2VyIG9uL29mZiBzdGF0dXMgYml0 Lg0KPiArICogQGN0bF9vZmZzOiBUaGUgb2Zmc2V0IGZvciBtYWluIHBvd2VyIGNvbnRyb2wgcmVn aXN0ZXIuDQo+ICsgKiBAc3JhbV9wZG5fYml0czogVGhlIG1hc2sgZm9yIHNyYW0gcG93ZXIgY29u dHJvbCBiaXRzLg0KPiArICogQHNyYW1fcGRuX2Fja19iaXRzOiBUaGUgbWFzayBmb3Igc3JhbSBw b3dlciBjb250cm9sIGFja2VkIGJpdHMuDQo+ICsgKiBAY2FwczogVGhlIGZsYWcgZm9yIGFjdGl2 ZSB3YWtlLXVwIGFjdGlvbi4NCj4gKyAqIEBicF9pbmZyYWNmZzogYnVzIHByb3RlY3Rpb24gZm9y IGluZnJhY2ZnIHN1YnN5c3RlbQ0KPiArICovDQo+ICtzdHJ1Y3Qgc2Nwc3lzX2RvbWFpbl9kYXRh IHsNCj4gKwl1MzIgc3RhX21hc2s7DQo+ICsJaW50IGN0bF9vZmZzOw0KPiArCXUzMiBzcmFtX3Bk bl9iaXRzOw0KPiArCXUzMiBzcmFtX3Bkbl9hY2tfYml0czsNCj4gKwl1OCBjYXBzOw0KPiArCWNv bnN0IHN0cnVjdCBzY3BzeXNfYnVzX3Byb3RfZGF0YSBicF9pbmZyYWNmZzsNCj4gK307DQo+ICsN Cj4gK3N0cnVjdCBzY3BzeXNfZG9tYWluIHsNCj4gKwlzdHJ1Y3QgZ2VuZXJpY19wbV9kb21haW4g Z2VucGQ7DQo+ICsJY29uc3Qgc3RydWN0IHNjcHN5c19kb21haW5fZGF0YSAqZGF0YTsNCj4gKwlz dHJ1Y3Qgc2Nwc3lzICpzY3BzeXM7DQo+ICsJaW50IG51bV9jbGtzOw0KPiArCXN0cnVjdCBjbGtf YnVsa19kYXRhICpjbGtzOw0KPiArCXN0cnVjdCByZWdtYXAgKmluZnJhY2ZnOw0KDQpDb3VsZCB3 ZSBtb3ZlDQpzdHJ1Y3QgcmVnbWFwICppbmZyYWNmZzsNCmJhY2sgdG8gc3RydWN0IHNjcHN5cz8g SXQgc2VlbXMgd2UgbmVlZCB0byBzZXQgdGhpcyBwcm9wZXJ0eSBtYW55IHRpbWVzDQp1bmRlciBl YWNoIHBvd2VyIGRvbWFpbiBzdWIgbm9kZSBpbiBkZXZpY2UgdHJlZT8NCg0KPiArfTsNCj4gKw0K PiArc3RydWN0IHNjcHN5c19zb2NfZGF0YSB7DQo+ICsJY29uc3Qgc3RydWN0IHNjcHN5c19kb21h aW5fZGF0YSAqZG9tYWluczsNCj4gKwlpbnQgbnVtX2RvbWFpbnM7DQo+ICsJaW50IHB3cl9zdGFf b2ZmczsNCj4gKwlpbnQgcHdyX3N0YTJuZF9vZmZzOw0KPiArfTsNCj4gKw0KPiArc3RydWN0IHNj cHN5cyB7DQo+ICsJc3RydWN0IGRldmljZSAqZGV2Ow0KPiArCXZvaWQgX19pb21lbSAqYmFzZTsN Cj4gKwljb25zdCBzdHJ1Y3Qgc2Nwc3lzX3NvY19kYXRhICpzb2NfZGF0YTsNCj4gKwlzdHJ1Y3Qg Z2VucGRfb25lY2VsbF9kYXRhIHBkX2RhdGE7DQo+ICsJc3RydWN0IGdlbmVyaWNfcG1fZG9tYWlu ICpkb21haW5zW107DQo+ICt9Ow0KPiArDQo+ICsjZGVmaW5lIHRvX3NjcHN5c19kb21haW4oZ3Bk KSBjb250YWluZXJfb2YoZ3BkLCBzdHJ1Y3Qgc2Nwc3lzX2RvbWFpbiwgZ2VucGQpDQo+ICsNCj4g K3N0YXRpYyBpbnQgc2Nwc3lzX2RvbWFpbl9pc19vbihzdHJ1Y3Qgc2Nwc3lzX2RvbWFpbiAqcGQp DQo+ICt7DQo+ICsJc3RydWN0IHNjcHN5cyAqc2Nwc3lzID0gcGQtPnNjcHN5czsNCj4gKw0KPiAr CXUzMiBzdGF0dXMgPSByZWFkbChzY3BzeXMtPmJhc2UgKyBzY3BzeXMtPnNvY19kYXRhLT5wd3Jf c3RhX29mZnMpICYgcGQtPmRhdGEtPnN0YV9tYXNrOw0KPiArCXUzMiBzdGF0dXMyID0gcmVhZGwo c2Nwc3lzLT5iYXNlICsgc2Nwc3lzLT5zb2NfZGF0YS0+cHdyX3N0YTJuZF9vZmZzKSAmIHBkLT5k YXRhLT5zdGFfbWFzazsNCj4gKw0KPiArCS8qDQo+ICsJICogQSBkb21haW4gaXMgb24gd2hlbiBi b3RoIHN0YXR1cyBiaXRzIGFyZSBzZXQuIElmIG9ubHkgb25lIGlzIHNldA0KPiArCSAqIHJldHVy biBhbiBlcnJvci4gVGhpcyBoYXBwZW5zIHdoaWxlIHBvd2VyaW5nIHVwIGEgZG9tYWluDQo+ICsJ ICovDQo+ICsNCj4gKwlpZiAoc3RhdHVzICYmIHN0YXR1czIpDQo+ICsJCXJldHVybiB0cnVlOw0K PiArCWlmICghc3RhdHVzICYmICFzdGF0dXMyKQ0KPiArCQlyZXR1cm4gZmFsc2U7DQo+ICsNCj4g KwlyZXR1cm4gLUVJTlZBTDsNCj4gK30NCj4gKw0KPiArc3RhdGljIGludCBzY3BzeXNfc3JhbV9l bmFibGUoc3RydWN0IHNjcHN5c19kb21haW4gKnBkLCB2b2lkIF9faW9tZW0gKmN0bF9hZGRyKQ0K PiArew0KPiArCXUzMiBwZG5fYWNrID0gcGQtPmRhdGEtPnNyYW1fcGRuX2Fja19iaXRzOw0KPiAr CXUzMiB2YWw7DQo+ICsJaW50IHRtcDsNCj4gKwlpbnQgcmV0Ow0KPiArDQo+ICsJdmFsID0gcmVh ZGwoY3RsX2FkZHIpOw0KPiArCXZhbCAmPSB+cGQtPmRhdGEtPnNyYW1fcGRuX2JpdHM7DQo+ICsJ d3JpdGVsKHZhbCwgY3RsX2FkZHIpOw0KPiArDQo+ICsJLyogRWl0aGVyIHdhaXQgdW50aWwgU1JB TV9QRE5fQUNLIGFsbCAxIG9yIDAgKi8NCj4gKwlyZXQgPSByZWFkbF9wb2xsX3RpbWVvdXQoY3Rs X2FkZHIsIHRtcCwgKHRtcCAmIHBkbl9hY2spID09IDAsIE1US19QT0xMX0RFTEFZX1VTLA0KPiAr CQkJCSBNVEtfUE9MTF9USU1FT1VUKTsNCj4gKwlpZiAocmV0IDwgMCkNCj4gKwkJcmV0dXJuIHJl dDsNCj4gKw0KPiArCXJldHVybiAwOw0KPiArfQ0KPiArDQo+ICtzdGF0aWMgaW50IHNjcHN5c19z cmFtX2Rpc2FibGUoc3RydWN0IHNjcHN5c19kb21haW4gKnBkLCB2b2lkIF9faW9tZW0gKmN0bF9h ZGRyKQ0KPiArew0KPiArCXUzMiBwZG5fYWNrID0gcGQtPmRhdGEtPnNyYW1fcGRuX2Fja19iaXRz Ow0KPiArCXUzMiB2YWw7DQo+ICsJaW50IHRtcDsNCj4gKw0KPiArCXZhbCA9IHJlYWRsKGN0bF9h ZGRyKTsNCj4gKwl2YWwgfD0gcGQtPmRhdGEtPnNyYW1fcGRuX2JpdHM7DQo+ICsJd3JpdGVsKHZh bCwgY3RsX2FkZHIpOw0KPiArDQo+ICsJLyogRWl0aGVyIHdhaXQgdW50aWwgU1JBTV9QRE5fQUNL IGFsbCAxIG9yIDAgKi8NCj4gKwlyZXR1cm4gcmVhZGxfcG9sbF90aW1lb3V0KGN0bF9hZGRyLCB0 bXAsICh0bXAgJiBwZG5fYWNrKSA9PSBwZG5fYWNrLCBNVEtfUE9MTF9ERUxBWV9VUywNCj4gKwkJ CQkgIE1US19QT0xMX1RJTUVPVVQpOw0KPiArfQ0KPiArDQo+ICtzdGF0aWMgaW50IHNjcHN5c19i dXNfcHJvdGVjdF9lbmFibGUoc3RydWN0IHNjcHN5c19kb21haW4gKnBkKQ0KPiArew0KPiArCWNv bnN0IHN0cnVjdCBzY3BzeXNfYnVzX3Byb3RfZGF0YSAqYnBfZGF0YSA9ICZwZC0+ZGF0YS0+YnBf aW5mcmFjZmc7DQo+ICsNCj4gKwlpZiAoIWJwX2RhdGEtPmJ1c19wcm90X21hc2spDQo+ICsJCXJl dHVybiAwOw0KPiArDQo+ICsJcmV0dXJuIG10a19pbmZyYWNmZ19zZXRfYnVzX3Byb3RlY3Rpb24o cGQtPmluZnJhY2ZnLCBicF9kYXRhLT5idXNfcHJvdF9tYXNrLA0KPiArCQkJCQkgICAgICAgYnBf ZGF0YS0+YnVzX3Byb3RfcmVnX3VwZGF0ZSk7DQo+ICt9DQo+ICsNCj4gK3N0YXRpYyBpbnQgc2Nw c3lzX2J1c19wcm90ZWN0X2Rpc2FibGUoc3RydWN0IHNjcHN5c19kb21haW4gKnBkKQ0KPiArew0K PiArCWNvbnN0IHN0cnVjdCBzY3BzeXNfYnVzX3Byb3RfZGF0YSAqYnBfZGF0YSA9ICZwZC0+ZGF0 YS0+YnBfaW5mcmFjZmc7DQo+ICsNCj4gKwlpZiAoIWJwX2RhdGEtPmJ1c19wcm90X21hc2spDQo+ ICsJCXJldHVybiAwOw0KPiArDQo+ICsJcmV0dXJuIG10a19pbmZyYWNmZ19jbGVhcl9idXNfcHJv dGVjdGlvbihwZC0+aW5mcmFjZmcsIGJwX2RhdGEtPmJ1c19wcm90X21hc2ssDQo+ICsJCQkJCQkg YnBfZGF0YS0+YnVzX3Byb3RfcmVnX3VwZGF0ZSk7DQo+ICt9DQo+ICsNCj4gK3N0YXRpYyBpbnQg c2Nwc3lzX3Bvd2VyX29uKHN0cnVjdCBnZW5lcmljX3BtX2RvbWFpbiAqZ2VucGQpDQo+ICt7DQo+ ICsJc3RydWN0IHNjcHN5c19kb21haW4gKnBkID0gY29udGFpbmVyX29mKGdlbnBkLCBzdHJ1Y3Qg c2Nwc3lzX2RvbWFpbiwgZ2VucGQpOw0KPiArCXN0cnVjdCBzY3BzeXMgKnNjcHN5cyA9IHBkLT5z Y3BzeXM7DQo+ICsJdm9pZCBfX2lvbWVtICpjdGxfYWRkciA9IHNjcHN5cy0+YmFzZSArIHBkLT5k YXRhLT5jdGxfb2ZmczsNCj4gKwlpbnQgcmV0LCB0bXA7DQo+ICsJdTMyIHZhbDsNCj4gKw0KPiAr CXJldCA9IGNsa19idWxrX2VuYWJsZShwZC0+bnVtX2Nsa3MsIHBkLT5jbGtzKTsNCj4gKwlpZiAo cmV0KQ0KPiArCQlyZXR1cm4gcmV0Ow0KPiArDQo+ICsJLyogc3Vic3lzIHBvd2VyIG9uICovDQo+ ICsJdmFsID0gcmVhZGwoY3RsX2FkZHIpOw0KPiArCXZhbCB8PSBQV1JfT05fQklUOw0KPiArCXdy aXRlbCh2YWwsIGN0bF9hZGRyKTsNCj4gKwl2YWwgfD0gUFdSX09OXzJORF9CSVQ7DQo+ICsJd3Jp dGVsKHZhbCwgY3RsX2FkZHIpOw0KPiArDQo+ICsJLyogd2FpdCB1bnRpbCBQV1JfQUNLID0gMSAq Lw0KPiArCXJldCA9IHJlYWR4X3BvbGxfdGltZW91dChzY3BzeXNfZG9tYWluX2lzX29uLCBwZCwg dG1wLCB0bXAgPiAwLCBNVEtfUE9MTF9ERUxBWV9VUywNCj4gKwkJCQkgTVRLX1BPTExfVElNRU9V VCk7DQo+ICsJaWYgKHJldCA8IDApDQo+ICsJCWdvdG8gZXJyX3B3cl9hY2s7DQo+ICsNCj4gKwl2 YWwgJj0gflBXUl9DTEtfRElTX0JJVDsNCj4gKwl3cml0ZWwodmFsLCBjdGxfYWRkcik7DQo+ICsN Cj4gKwl2YWwgJj0gflBXUl9JU09fQklUOw0KPiArCXdyaXRlbCh2YWwsIGN0bF9hZGRyKTsNCj4g Kw0KPiArCXZhbCB8PSBQV1JfUlNUX0JfQklUOw0KPiArCXdyaXRlbCh2YWwsIGN0bF9hZGRyKTsN Cj4gKw0KPiArCXJldCA9IHNjcHN5c19zcmFtX2VuYWJsZShwZCwgY3RsX2FkZHIpOw0KPiArCWlm IChyZXQgPCAwKQ0KPiArCQlnb3RvIGVycl9wd3JfYWNrOw0KPiArDQo+ICsJcmV0ID0gc2Nwc3lz X2J1c19wcm90ZWN0X2Rpc2FibGUocGQpOw0KPiArCWlmIChyZXQgPCAwKQ0KPiArCQlnb3RvIGVy cl9wd3JfYWNrOw0KPiArDQo+ICsJcmV0dXJuIDA7DQo+ICsNCj4gK2Vycl9wd3JfYWNrOg0KPiAr CWNsa19idWxrX2Rpc2FibGUocGQtPm51bV9jbGtzLCBwZC0+Y2xrcyk7DQo+ICsJZGV2X2Vycihz Y3BzeXMtPmRldiwgIkZhaWxlZCB0byBwb3dlciBvbiBkb21haW4gJXNcbiIsIGdlbnBkLT5uYW1l KTsNCj4gKw0KPiArCXJldHVybiByZXQ7DQo+ICt9DQo+ICsNCj4gK3N0YXRpYyBpbnQgc2Nwc3lz X3Bvd2VyX29mZihzdHJ1Y3QgZ2VuZXJpY19wbV9kb21haW4gKmdlbnBkKQ0KPiArew0KPiArCXN0 cnVjdCBzY3BzeXNfZG9tYWluICpwZCA9IGNvbnRhaW5lcl9vZihnZW5wZCwgc3RydWN0IHNjcHN5 c19kb21haW4sIGdlbnBkKTsNCj4gKwlzdHJ1Y3Qgc2Nwc3lzICpzY3BzeXMgPSBwZC0+c2Nwc3lz Ow0KPiArCXZvaWQgX19pb21lbSAqY3RsX2FkZHIgPSBzY3BzeXMtPmJhc2UgKyBwZC0+ZGF0YS0+ Y3RsX29mZnM7DQo+ICsJaW50IHJldCwgdG1wOw0KPiArCXUzMiB2YWw7DQo+ICsNCj4gKwlyZXQg PSBzY3BzeXNfYnVzX3Byb3RlY3RfZW5hYmxlKHBkKTsNCj4gKwlpZiAocmV0IDwgMCkNCj4gKwkJ cmV0dXJuIHJldDsNCj4gKw0KPiArCXJldCA9IHNjcHN5c19zcmFtX2Rpc2FibGUocGQsIGN0bF9h ZGRyKTsNCj4gKwlpZiAocmV0IDwgMCkNCj4gKwkJcmV0dXJuIHJldDsNCj4gKw0KPiArCS8qIHN1 YnN5cyBwb3dlciBvZmYgKi8NCj4gKwl2YWwgPSByZWFkbChjdGxfYWRkcik7DQo+ICsJdmFsIHw9 IFBXUl9JU09fQklUOw0KPiArCXdyaXRlbCh2YWwsIGN0bF9hZGRyKTsNCj4gKw0KPiArCXZhbCAm PSB+UFdSX1JTVF9CX0JJVDsNCj4gKwl3cml0ZWwodmFsLCBjdGxfYWRkcik7DQo+ICsNCj4gKwl2 YWwgfD0gUFdSX0NMS19ESVNfQklUOw0KPiArCXdyaXRlbCh2YWwsIGN0bF9hZGRyKTsNCj4gKw0K PiArCXZhbCAmPSB+UFdSX09OX0JJVDsNCj4gKwl3cml0ZWwodmFsLCBjdGxfYWRkcik7DQo+ICsN Cj4gKwl2YWwgJj0gflBXUl9PTl8yTkRfQklUOw0KPiArCXdyaXRlbCh2YWwsIGN0bF9hZGRyKTsN Cj4gKw0KPiArCS8qIHdhaXQgdW50aWwgUFdSX0FDSyA9IDAgKi8NCj4gKwlyZXQgPSByZWFkeF9w b2xsX3RpbWVvdXQoc2Nwc3lzX2RvbWFpbl9pc19vbiwgcGQsIHRtcCwgdG1wID09IDAsIE1US19Q T0xMX0RFTEFZX1VTLA0KPiArCQkJCSBNVEtfUE9MTF9USU1FT1VUKTsNCj4gKwlpZiAocmV0IDwg MCkNCj4gKwkJcmV0dXJuIHJldDsNCj4gKw0KPiArCWNsa19idWxrX2Rpc2FibGUocGQtPm51bV9j bGtzLCBwZC0+Y2xrcyk7DQo+ICsNCj4gKwlyZXR1cm4gMDsNCj4gK30NCj4gKw0KPiArc3RhdGlj IGludCBzY3BzeXNfYWRkX29uZV9kb21haW4oc3RydWN0IHNjcHN5cyAqc2Nwc3lzLCBzdHJ1Y3Qg ZGV2aWNlX25vZGUgKm5vZGUpDQo+ICt7DQo+ICsJY29uc3Qgc3RydWN0IHNjcHN5c19kb21haW5f ZGF0YSAqZG9tYWluX2RhdGE7DQo+ICsJc3RydWN0IHNjcHN5c19kb21haW4gKnBkOw0KPiArCWlu dCBpLCByZXQ7DQo+ICsJdTMyIGlkOw0KPiArDQo+ICsJcmV0ID0gb2ZfcHJvcGVydHlfcmVhZF91 MzIobm9kZSwgInJlZyIsICZpZCk7DQo+ICsJaWYgKHJldCkgew0KPiArCQlkZXZfZXJyKHNjcHN5 cy0+ZGV2LCAiJXBPRm46IGZhaWxlZCB0byByZXRyaWV2ZSBkb21haW4gaWQgZnJvbSByZWc6ICVk XG4iLCBub2RlLA0KPiArCQkJcmV0KTsNCj4gKwkJcmV0dXJuIC1FSU5WQUw7DQo+ICsJfQ0KPiAr DQo+ICsJaWYgKGlkID49IHNjcHN5cy0+c29jX2RhdGEtPm51bV9kb21haW5zKSB7DQo+ICsJCWRl dl9lcnIoc2Nwc3lzLT5kZXYsICIlcE9GbjogaW52YWxpZCBkb21haW4gaWQgJWRcbiIsIG5vZGUs IGlkKTsNCj4gKwkJcmV0dXJuIC1FSU5WQUw7DQo+ICsJfQ0KPiArDQo+ICsJZG9tYWluX2RhdGEg PSAmc2Nwc3lzLT5zb2NfZGF0YS0+ZG9tYWluc1tpZF07DQo+ICsJaWYgKCFkb21haW5fZGF0YSkg ew0KPiArCQlkZXZfZXJyKHNjcHN5cy0+ZGV2LCAiJXBPRm46IHVuZGVmaW5lZCBkb21haW4gaWQg JWRcbiIsIG5vZGUsIGlkKTsNCj4gKwkJcmV0dXJuIC1FSU5WQUw7DQo+ICsJfQ0KPiArDQo+ICsJ cGQgPSBkZXZtX2t6YWxsb2Moc2Nwc3lzLT5kZXYsIHNpemVvZigqcGQpLCBHRlBfS0VSTkVMKTsN Cj4gKwlpZiAoIXBkKQ0KPiArCQlyZXR1cm4gLUVOT01FTTsNCj4gKw0KPiArCXBkLT5kYXRhID0g ZG9tYWluX2RhdGE7DQo+ICsJcGQtPnNjcHN5cyA9IHNjcHN5czsNCj4gKw0KPiArCXBkLT5pbmZy YWNmZyA9IHN5c2Nvbl9yZWdtYXBfbG9va3VwX2J5X3BoYW5kbGUobm9kZSwgIm1lZGlhdGVrLGlu ZnJhY2ZnIik7DQo+ICsJaWYgKElTX0VSUihwZC0+aW5mcmFjZmcpKQ0KPiArCQlwZC0+aW5mcmFj ZmcgPSBOVUxMOw0KPiArDQo+ICsJcGQtPm51bV9jbGtzID0gb2ZfY2xrX2dldF9wYXJlbnRfY291 bnQobm9kZSk7DQo+ICsJaWYgKHBkLT5udW1fY2xrcyA+IDApIHsNCj4gKwkJcGQtPmNsa3MgPSBk ZXZtX2tjYWxsb2Moc2Nwc3lzLT5kZXYsIHBkLT5udW1fY2xrcywgc2l6ZW9mKCpwZC0+Y2xrcyks IEdGUF9LRVJORUwpOw0KPiArCQlpZiAoIXBkLT5jbGtzKQ0KPiArCQkJcmV0dXJuIC1FTk9NRU07 DQo+ICsJfSBlbHNlIHsNCj4gKwkJcGQtPm51bV9jbGtzID0gMDsNCj4gKwl9DQo+ICsNCj4gKwlm b3IgKGkgPSAwOyBpIDwgcGQtPm51bV9jbGtzOyBpKyspIHsNCj4gKwkJcGQtPmNsa3NbaV0uY2xr ID0gb2ZfY2xrX2dldChub2RlLCBpKTsNCg0KSXMgaXQgcG9zc2libGUgdG8gaGF2ZSBhIGJldHRl ciB3YXkgdGhhdCB3ZSBjb3VsZCB1c2Ugb2ZfY2xrX2J1bGtfZ2V0KCk/DQoNCj4gKwkJaWYgKElT X0VSUihwZC0+Y2xrc1tpXS5jbGspKSB7DQo+ICsJCQlyZXQgPSBQVFJfRVJSKHBkLT5jbGtzW2ld LmNsayk7DQo+ICsJCQlkZXZfZXJyKHNjcHN5cy0+ZGV2LCAiJXBPRm46IGZhaWxlZCB0byBnZXQg Y2xrIGF0IGluZGV4ICVkOiAlZFxuIiwgbm9kZSwgaSwNCj4gKwkJCQlyZXQpOw0KPiArCQkJcmV0 dXJuIHJldDsNCj4gKwkJfQ0KPiArCX0NCj4gKw0KPiArCXJldCA9IGNsa19idWxrX3ByZXBhcmUo cGQtPm51bV9jbGtzLCBwZC0+Y2xrcyk7DQo+ICsJaWYgKHJldCkNCj4gKwkJZ290byBlcnJfcHV0 X2Nsb2NrczsNCj4gKw0KPiArCS8qDQo+ICsJICogSW5pdGlhbGx5IHR1cm4gb24gYWxsIGRvbWFp bnMgdG8gbWFrZSB0aGUgZG9tYWlucyB1c2FibGUNCj4gKwkgKiB3aXRoICFDT05GSUdfUE0gYW5k IHRvIGdldCB0aGUgaGFyZHdhcmUgaW4gc3luYyB3aXRoIHRoZQ0KPiArCSAqIHNvZnR3YXJlLiAg VGhlIHVudXNlZCBkb21haW5zIHdpbGwgYmUgc3dpdGNoZWQgb2ZmIGR1cmluZw0KPiArCSAqIGxh dGVfaW5pdCB0aW1lLg0KPiArCSAqLw0KPiArCXJldCA9IHNjcHN5c19wb3dlcl9vbigmcGQtPmdl bnBkKTsNCj4gKwlpZiAocmV0IDwgMCkgew0KPiArCQlkZXZfZXJyKHNjcHN5cy0+ZGV2LCAiZmFp bGVkIHRvIHBvd2VyIG9uIGRvbWFpbiAlcE9GTiB3aXRoIGVycm9yICVkXG4iLCBub2RlLCByZXQp Ow0KPiArCQlnb3RvIGVycl91bnByZXBhcmVfY2xvY2tzOw0KPiArCX0NCj4gKw0KPiArCXBkLT5n ZW5wZC5uYW1lID0gbm9kZS0+bmFtZTsNCj4gKwlwZC0+Z2VucGQucG93ZXJfb2ZmID0gc2Nwc3lz X3Bvd2VyX29mZjsNCj4gKwlwZC0+Z2VucGQucG93ZXJfb24gPSBzY3BzeXNfcG93ZXJfb247DQo+ ICsNCj4gKwlwbV9nZW5wZF9pbml0KCZwZC0+Z2VucGQsIE5VTEwsIGZhbHNlKTsNCj4gKw0KPiAr CXNjcHN5cy0+ZG9tYWluc1tpZF0gPSAmcGQtPmdlbnBkOw0KPiArCXJldHVybiAwOw0KPiArDQo+ ICtlcnJfdW5wcmVwYXJlX2Nsb2NrczoNCj4gKwljbGtfYnVsa191bnByZXBhcmUocGQtPm51bV9j bGtzLCBwZC0+Y2xrcyk7DQo+ICtlcnJfcHV0X2Nsb2NrczoNCj4gKwljbGtfYnVsa19wdXQocGQt Pm51bV9jbGtzLCBwZC0+Y2xrcyk7DQo+ICsJZGV2bV9rZnJlZShzY3BzeXMtPmRldiwgcGQtPmNs a3MpOw0KPiArCXBkLT5udW1fY2xrcyA9IDA7DQo+ICsJcmV0dXJuIHJldDsNCj4gK30NCj4gKw0K PiArc3RhdGljIGludCBzY3BzeXNfYWRkX3N1YmRvbWFpbihzdHJ1Y3Qgc2Nwc3lzICpzY3BzeXMs IHN0cnVjdCBkZXZpY2Vfbm9kZSAqcGFyZW50KQ0KPiArew0KPiArCXN0cnVjdCBkZXZpY2Vfbm9k ZSAqY2hpbGQ7DQo+ICsJc3RydWN0IGdlbmVyaWNfcG1fZG9tYWluICpjaGlsZF9wZCwgKnBhcmVu dF9wZDsNCj4gKwlpbnQgcmV0Ow0KPiArDQo+ICsJZm9yX2VhY2hfY2hpbGRfb2Zfbm9kZShwYXJl bnQsIGNoaWxkKSB7DQo+ICsJCXUzMiBpZDsNCj4gKw0KPiArCQlyZXQgPSBvZl9wcm9wZXJ0eV9y ZWFkX3UzMihwYXJlbnQsICJyZWciLCAmaWQpOw0KPiArCQlpZiAocmV0KSB7DQo+ICsJCQlkZXZf ZXJyKHNjcHN5cy0+ZGV2LCAiJXBPRm46IGZhaWxlZCB0byBnZXQgcGFyZW50IGRvbWFpbiBpZDog JWRcbiIsIGNoaWxkLA0KPiArCQkJCXJldCk7DQo+ICsJCQlnb3RvIGVycl9wdXRfbm9kZTsNCj4g KwkJfQ0KPiArCQlwYXJlbnRfcGQgPSBzY3BzeXMtPnBkX2RhdGEuZG9tYWluc1tpZF07DQo+ICsN Cg0Kbml0LiBDb3VsZCB3ZSBtb3ZlIHBhcmVudCBvdXRzaWRlKGluIGZyb250IG9mKSB0aGUgbG9v cD8NCg0KPiArCQlyZXQgPSBzY3BzeXNfYWRkX29uZV9kb21haW4oc2Nwc3lzLCBjaGlsZCk7DQo+ ICsJCWlmIChyZXQpIHsNCj4gKwkJCWRldl9lcnIoc2Nwc3lzLT5kZXYsICJlcnJvciBhZGRpbmcg cG93ZXIgZG9tYWluIGZvciAlcE9GbjogJWRcbiIsIGNoaWxkLA0KPiArCQkJCXJldCk7DQo+ICsJ CQlnb3RvIGVycl9wdXRfbm9kZTsNCj4gKwkJfQ0KPiArDQo+ICsJCXJldCA9IG9mX3Byb3BlcnR5 X3JlYWRfdTMyKGNoaWxkLCAicmVnIiwgJmlkKTsNCj4gKwkJaWYgKHJldCkgew0KPiArCQkJZGV2 X2VycihzY3BzeXMtPmRldiwgIiVwT0ZuOiBmYWlsZWQgdG8gZ2V0IGNoaWxkIGRvbWFpbiBpZDog JWRcbiIsIGNoaWxkLA0KPiArCQkJCXJldCk7DQo+ICsJCQlnb3RvIGVycl9wdXRfbm9kZTsNCj4g KwkJfQ0KPiArCQljaGlsZF9wZCA9IHNjcHN5cy0+cGRfZGF0YS5kb21haW5zW2lkXTsNCj4gKw0K PiArCQlyZXQgPSBwbV9nZW5wZF9hZGRfc3ViZG9tYWluKHBhcmVudF9wZCwgY2hpbGRfcGQpOw0K PiArCQlpZiAocmV0KSB7DQo+ICsJCQlkZXZfZXJyKHNjcHN5cy0+ZGV2LCAiZmFpbGVkIHRvIGFk ZCAlcyBzdWJkb21haW4gdG8gcGFyZW50ICVzXG4iLA0KPiArCQkJCWNoaWxkX3BkLT5uYW1lLCBw YXJlbnRfcGQtPm5hbWUpOw0KPiArCQkJZ290byBlcnJfcHV0X25vZGU7DQo+ICsJCX0gZWxzZSB7 DQo+ICsJCQlkZXZfZGJnKHNjcHN5cy0+ZGV2LCAiJXMgYWRkIHN1YmRvbWFpbjogJXNcbiIsIHBh cmVudF9wZC0+bmFtZSwNCj4gKwkJCQljaGlsZF9wZC0+bmFtZSk7DQo+ICsJCX0NCj4gKw0KPiAr CQkvKiByZWN1cnNpdmUgY2FsbCB0byBhZGQgYWxsIHN1YmRvbWFpbnMgKi8NCj4gKwkJcmV0ID0g c2Nwc3lzX2FkZF9zdWJkb21haW4oc2Nwc3lzLCBjaGlsZCk7DQo+ICsJCWlmIChyZXQpDQo+ICsJ CQlnb3RvIGVycl9wdXRfbm9kZTsNCj4gKwl9DQo+ICsNCj4gKwlyZXR1cm4gMDsNCj4gKw0KPiAr ZXJyX3B1dF9ub2RlOg0KPiArCW9mX25vZGVfcHV0KGNoaWxkKTsNCj4gKwlyZXR1cm4gcmV0Ow0K PiArfQ0KPiArDQo+ICtzdGF0aWMgdm9pZCBzY3BzeXNfcmVtb3ZlX29uZV9kb21haW4oc3RydWN0 IHNjcHN5c19kb21haW4gKnBkKQ0KPiArew0KPiArCWludCByZXQ7DQo+ICsNCj4gKwkvKg0KPiAr CSAqIFdlJ3JlIGluIHRoZSBlcnJvciBjbGVhbnVwIGFscmVhZHksIHNvIHdlIG9ubHkgY29tcGxh aW4sDQo+ICsJICogYnV0IHdvbid0IGVtaXQgYW5vdGhlciBlcnJvciBvbiB0b3Agb2YgdGhlIG9y aWdpbmFsIG9uZS4NCj4gKwkgKi8NCj4gKwlyZXQgPSBwbV9nZW5wZF9yZW1vdmUoJnBkLT5nZW5w ZCk7DQo+ICsJaWYgKHJldCA8IDApDQo+ICsJCWRldl9lcnIocGQtPnNjcHN5cy0+ZGV2LA0KPiAr CQkJImZhaWxlZCB0byByZW1vdmUgZG9tYWluICclcycgOiAlZCAtIHN0YXRlIG1heSBiZSBpbmNv bnNpc3RlbnRcbiIsDQo+ICsJCQlwZC0+Z2VucGQubmFtZSwgcmV0KTsNCj4gKw0KPiArCXNjcHN5 c19wb3dlcl9vZmYoJnBkLT5nZW5wZCk7DQo+ICsNCj4gKwljbGtfYnVsa191bnByZXBhcmUocGQt Pm51bV9jbGtzLCBwZC0+Y2xrcyk7DQo+ICsJY2xrX2J1bGtfcHV0KHBkLT5udW1fY2xrcywgcGQt PmNsa3MpOw0KPiArCXBkLT5udW1fY2xrcyA9IDA7DQo+ICt9DQo+ICsNCj4gK3N0YXRpYyB2b2lk IHNjcHN5c19kb21haW5fY2xlYW51cChzdHJ1Y3Qgc2Nwc3lzICpzY3BzeXMpDQo+ICt7DQo+ICsJ c3RydWN0IGdlbmVyaWNfcG1fZG9tYWluICpnZW5wZDsNCj4gKwlzdHJ1Y3Qgc2Nwc3lzX2RvbWFp biAqcGQ7DQo+ICsJaW50IGk7DQo+ICsNCj4gKwlmb3IgKGkgPSBzY3BzeXMtPnBkX2RhdGEubnVt X2RvbWFpbnMgLSAxOyBpID49IDA7IGktLSkgew0KPiArCQlnZW5wZCA9IHNjcHN5cy0+cGRfZGF0 YS5kb21haW5zW2ldOw0KPiArCQlpZiAoZ2VucGQpIHsNCj4gKwkJCXBkID0gdG9fc2Nwc3lzX2Rv bWFpbihnZW5wZCk7DQo+ICsJCQlzY3BzeXNfcmVtb3ZlX29uZV9kb21haW4ocGQpOw0KPiArCQl9 DQo+ICsJfQ0KPiArfQ0KPiArDQo+ICsvKg0KPiArICogTVQ4MTczIHBvd2VyIGRvbWFpbiBzdXBw b3J0DQo+ICsgKi8NCj4gKw0KPiArc3RhdGljIGNvbnN0IHN0cnVjdCBzY3BzeXNfZG9tYWluX2Rh dGEgc2Nwc3lzX2RvbWFpbl9kYXRhX210ODE3M1tdID0gew0KPiArCVtNVDgxNzNfUE9XRVJfRE9N QUlOX1ZERUNdID0gew0KPiArCQkuc3RhX21hc2sgPSBQV1JfU1RBVFVTX1ZERUMsDQo+ICsJCS5j dGxfb2ZmcyA9IFNQTV9WREVfUFdSX0NPTiwNCj4gKwkJLnNyYW1fcGRuX2JpdHMgPSBHRU5NQVNL KDExLCA4KSwNCj4gKwkJLnNyYW1fcGRuX2Fja19iaXRzID0gR0VOTUFTSygxMiwgMTIpLA0KPiAr CX0sDQo+ICsJW01UODE3M19QT1dFUl9ET01BSU5fVkVOQ10gPSB7DQo+ICsJCS5zdGFfbWFzayA9 IFBXUl9TVEFUVVNfVkVOQywNCj4gKwkJLmN0bF9vZmZzID0gU1BNX1ZFTl9QV1JfQ09OLA0KPiAr CQkuc3JhbV9wZG5fYml0cyA9IEdFTk1BU0soMTEsIDgpLA0KPiArCQkuc3JhbV9wZG5fYWNrX2Jp dHMgPSBHRU5NQVNLKDE1LCAxMiksDQo+ICsJfSwNCj4gKwlbTVQ4MTczX1BPV0VSX0RPTUFJTl9J U1BdID0gew0KPiArCQkuc3RhX21hc2sgPSBQV1JfU1RBVFVTX0lTUCwNCj4gKwkJLmN0bF9vZmZz ID0gU1BNX0lTUF9QV1JfQ09OLA0KPiArCQkuc3JhbV9wZG5fYml0cyA9IEdFTk1BU0soMTEsIDgp LA0KPiArCQkuc3JhbV9wZG5fYWNrX2JpdHMgPSBHRU5NQVNLKDEzLCAxMiksDQo+ICsJfSwNCj4g KwlbTVQ4MTczX1BPV0VSX0RPTUFJTl9NTV0gPSB7DQo+ICsJCS5zdGFfbWFzayA9IFBXUl9TVEFU VVNfRElTUCwNCj4gKwkJLmN0bF9vZmZzID0gU1BNX0RJU19QV1JfQ09OLA0KPiArCQkuc3JhbV9w ZG5fYml0cyA9IEdFTk1BU0soMTEsIDgpLA0KPiArCQkuc3JhbV9wZG5fYWNrX2JpdHMgPSBHRU5N QVNLKDEyLCAxMiksDQo+ICsJCS5icF9pbmZyYWNmZyA9IHsNCj4gKwkJCS5idXNfcHJvdF9yZWdf dXBkYXRlID0gdHJ1ZSwNCj4gKwkJCS5idXNfcHJvdF9tYXNrID0gTVQ4MTczX1RPUF9BWElfUFJP VF9FTl9NTV9NMCB8DQo+ICsJCQkJTVQ4MTczX1RPUF9BWElfUFJPVF9FTl9NTV9NMSwNCj4gKwkJ fSwNCj4gKwl9LA0KPiArCVtNVDgxNzNfUE9XRVJfRE9NQUlOX1ZFTkNfTFRdID0gew0KPiArCQku c3RhX21hc2sgPSBQV1JfU1RBVFVTX1ZFTkNfTFQsDQo+ICsJCS5jdGxfb2ZmcyA9IFNQTV9WRU4y X1BXUl9DT04sDQo+ICsJCS5zcmFtX3Bkbl9iaXRzID0gR0VOTUFTSygxMSwgOCksDQo+ICsJCS5z cmFtX3Bkbl9hY2tfYml0cyA9IEdFTk1BU0soMTUsIDEyKSwNCj4gKwl9LA0KPiArCVtNVDgxNzNf UE9XRVJfRE9NQUlOX0FVRElPXSA9IHsNCj4gKwkJLnN0YV9tYXNrID0gUFdSX1NUQVRVU19BVURJ TywNCj4gKwkJLmN0bF9vZmZzID0gU1BNX0FVRElPX1BXUl9DT04sDQo+ICsJCS5zcmFtX3Bkbl9i aXRzID0gR0VOTUFTSygxMSwgOCksDQo+ICsJCS5zcmFtX3Bkbl9hY2tfYml0cyA9IEdFTk1BU0so MTUsIDEyKSwNCj4gKwl9LA0KPiArCVtNVDgxNzNfUE9XRVJfRE9NQUlOX1VTQl0gPSB7DQo+ICsJ CS5zdGFfbWFzayA9IFBXUl9TVEFUVVNfVVNCLA0KPiArCQkuY3RsX29mZnMgPSBTUE1fVVNCX1BX Ul9DT04sDQo+ICsJCS5zcmFtX3Bkbl9iaXRzID0gR0VOTUFTSygxMSwgOCksDQo+ICsJCS5zcmFt X3Bkbl9hY2tfYml0cyA9IEdFTk1BU0soMTUsIDEyKSwNCj4gKwkJLmNhcHMgPSBNVEtfU0NQRF9B Q1RJVkVfV0FLRVVQLA0KPiArCX0sDQo+ICsJW01UODE3M19QT1dFUl9ET01BSU5fTUZHX0FTWU5D XSA9IHsNCj4gKwkJLnN0YV9tYXNrID0gUFdSX1NUQVRVU19NRkdfQVNZTkMsDQo+ICsJCS5jdGxf b2ZmcyA9IFNQTV9NRkdfQVNZTkNfUFdSX0NPTiwNCj4gKwkJLnNyYW1fcGRuX2JpdHMgPSBHRU5N QVNLKDExLCA4KSwNCj4gKwkJLnNyYW1fcGRuX2Fja19iaXRzID0gMCwNCj4gKwl9LA0KPiArCVtN VDgxNzNfUE9XRVJfRE9NQUlOX01GR18yRF0gPSB7DQo+ICsJCS5zdGFfbWFzayA9IFBXUl9TVEFU VVNfTUZHXzJELA0KPiArCQkuY3RsX29mZnMgPSBTUE1fTUZHXzJEX1BXUl9DT04sDQo+ICsJCS5z cmFtX3Bkbl9iaXRzID0gR0VOTUFTSygxMSwgOCksDQo+ICsJCS5zcmFtX3Bkbl9hY2tfYml0cyA9 IEdFTk1BU0soMTMsIDEyKSwNCj4gKwl9LA0KPiArCVtNVDgxNzNfUE9XRVJfRE9NQUlOX01GR10g PSB7DQo+ICsJCS5zdGFfbWFzayA9IFBXUl9TVEFUVVNfTUZHLA0KPiArCQkuY3RsX29mZnMgPSBT UE1fTUZHX1BXUl9DT04sDQo+ICsJCS5zcmFtX3Bkbl9iaXRzID0gR0VOTUFTSygxMywgOCksDQo+ ICsJCS5zcmFtX3Bkbl9hY2tfYml0cyA9IEdFTk1BU0soMjEsIDE2KSwNCj4gKwkJLmJwX2luZnJh Y2ZnID0gew0KPiArCQkJLmJ1c19wcm90X3JlZ191cGRhdGUgPSB0cnVlLA0KPiArCQkJLmJ1c19w cm90X21hc2sgPSBNVDgxNzNfVE9QX0FYSV9QUk9UX0VOX01GR19TIHwNCj4gKwkJCQlNVDgxNzNf VE9QX0FYSV9QUk9UX0VOX01GR19NMCB8DQo+ICsJCQkJTVQ4MTczX1RPUF9BWElfUFJPVF9FTl9N RkdfTTEgfA0KPiArCQkJCU1UODE3M19UT1BfQVhJX1BST1RfRU5fTUZHX1NOT09QX09VVCwNCj4g KwkJfSwNCj4gKwl9LA0KPiArfTsNCj4gKw0KPiArc3RhdGljIGNvbnN0IHN0cnVjdCBzY3BzeXNf c29jX2RhdGEgbXQ4MTczX3NjcHN5c19kYXRhID0gew0KPiArCS5kb21haW5zID0gc2Nwc3lzX2Rv bWFpbl9kYXRhX210ODE3MywNCj4gKwkubnVtX2RvbWFpbnMgPSBBUlJBWV9TSVpFKHNjcHN5c19k b21haW5fZGF0YV9tdDgxNzMpLA0KPiArCS5wd3Jfc3RhX29mZnMgPSBTUE1fUFdSX1NUQVRVUywN Cj4gKwkucHdyX3N0YTJuZF9vZmZzID0gU1BNX1BXUl9TVEFUVVNfMk5ELA0KPiArfTsNCj4gKw0K PiArc3RhdGljIGNvbnN0IHN0cnVjdCBvZl9kZXZpY2VfaWQgc2Nwc3lzX29mX21hdGNoW10gPSB7 DQo+ICsJew0KPiArCQkuY29tcGF0aWJsZSA9ICJtZWRpYXRlayxtdDgxNzMtcG93ZXItY29udHJv bGxlciIsDQo+ICsJCS5kYXRhID0gJm10ODE3M19zY3BzeXNfZGF0YSwNCj4gKwl9LA0KPiArCXsg fQ0KPiArfTsNCj4gKw0KPiArc3RhdGljIGludCBzY3BzeXNfcHJvYmUoc3RydWN0IHBsYXRmb3Jt X2RldmljZSAqcGRldikNCj4gK3sNCj4gKwlzdHJ1Y3QgZGV2aWNlICpkZXYgPSAmcGRldi0+ZGV2 Ow0KPiArCXN0cnVjdCBkZXZpY2Vfbm9kZSAqbnAgPSBkZXYtPm9mX25vZGU7DQo+ICsJY29uc3Qg c3RydWN0IHNjcHN5c19zb2NfZGF0YSAqc29jOw0KPiArCXN0cnVjdCBkZXZpY2Vfbm9kZSAqbm9k ZTsNCj4gKwlzdHJ1Y3Qgc2Nwc3lzICpzY3BzeXM7DQo+ICsJc3RydWN0IHJlc291cmNlICpyZXM7 DQo+ICsJaW50IHJldDsNCj4gKw0KPiArCXNvYyA9IG9mX2RldmljZV9nZXRfbWF0Y2hfZGF0YSgm cGRldi0+ZGV2KTsNCj4gKwlpZiAoIXNvYykgew0KPiArCQlkZXZfZXJyKCZwZGV2LT5kZXYsICJu byBwb3dlciBjb250cm9sbGVyIGRhdGFcbiIpOw0KPiArCQlyZXR1cm4gLUVJTlZBTDsNCj4gKwl9 DQo+ICsNCj4gKwlzY3BzeXMgPSBkZXZtX2t6YWxsb2MoZGV2LCBzdHJ1Y3Rfc2l6ZShzY3BzeXMs IGRvbWFpbnMsIHNvYy0+bnVtX2RvbWFpbnMpLCBHRlBfS0VSTkVMKTsNCj4gKwlpZiAoIXNjcHN5 cykNCj4gKwkJcmV0dXJuIC1FTk9NRU07DQo+ICsNCj4gKwlzY3BzeXMtPmRldiA9IGRldjsNCj4g KwlzY3BzeXMtPnNvY19kYXRhID0gc29jOw0KPiArDQo+ICsJc2Nwc3lzLT5wZF9kYXRhLmRvbWFp bnMgPSBzY3BzeXMtPmRvbWFpbnM7DQo+ICsJc2Nwc3lzLT5wZF9kYXRhLm51bV9kb21haW5zID0g c29jLT5udW1fZG9tYWluczsNCj4gKw0KPiArCXJlcyA9IHBsYXRmb3JtX2dldF9yZXNvdXJjZShw ZGV2LCBJT1JFU09VUkNFX01FTSwgMCk7DQo+ICsJc2Nwc3lzLT5iYXNlID0gZGV2bV9pb3JlbWFw X3Jlc291cmNlKGRldiwgcmVzKTsNCj4gKwlpZiAoSVNfRVJSKHNjcHN5cy0+YmFzZSkpDQo+ICsJ CXJldHVybiAtRU5PREVWOw0KPiArDQo+ICsJcmV0ID0gLUVOT0RFVjsNCj4gKwlmb3JfZWFjaF9h dmFpbGFibGVfY2hpbGRfb2Zfbm9kZShucCwgbm9kZSkgew0KPiArCQlyZXQgPSBzY3BzeXNfYWRk X29uZV9kb21haW4oc2Nwc3lzLCBub2RlKTsNCj4gKwkJaWYgKHJldCkgew0KPiArCQkJZGV2X2Vy cihkZXYsICJmYWlsZWQgdG8gaGFuZGxlIG5vZGUgJXBPRk46ICVkXG4iLCBub2RlLCByZXQpOw0K PiArCQkJb2Zfbm9kZV9wdXQobm9kZSk7DQo+ICsJCQlnb3RvIGVycl9jbGVhbnVwX2RvbWFpbnM7 DQo+ICsJCX0NCj4gKw0KPiArCQlyZXQgPSBzY3BzeXNfYWRkX3N1YmRvbWFpbihzY3BzeXMsIG5v ZGUpOw0KPiArCQlpZiAocmV0KSB7DQo+ICsJCQlkZXZfZXJyKGRldiwgImZhaWxlZCB0byBhZGQg c3ViZG9tYWluIG5vZGUgJXBPRm46ICVkXG4iLCBub2RlLCByZXQpOw0KPiArCQkJb2Zfbm9kZV9w dXQobm9kZSk7DQo+ICsJCQlnb3RvIGVycl9jbGVhbnVwX2RvbWFpbnM7DQo+ICsJCX0NCj4gKwl9 DQo+ICsNCj4gKwlpZiAocmV0KSB7DQo+ICsJCWRldl9kYmcoZGV2LCAibm8gcG93ZXIgZG9tYWlu cyBwcmVzZW50XG4iKTsNCj4gKwkJcmV0dXJuIHJldDsNCj4gKwl9DQo+ICsNCj4gKwlyZXQgPSBv Zl9nZW5wZF9hZGRfcHJvdmlkZXJfb25lY2VsbChucCwgJnNjcHN5cy0+cGRfZGF0YSk7DQo+ICsJ aWYgKHJldCkgew0KPiArCQlkZXZfZXJyKGRldiwgImZhaWxlZCB0byBhZGQgcHJvdmlkZXI6ICVk XG4iLCByZXQpOw0KPiArCQlnb3RvIGVycl9jbGVhbnVwX2RvbWFpbnM7DQo+ICsJfQ0KPiArDQo+ ICsJcmV0dXJuIDA7DQo+ICsNCj4gK2Vycl9jbGVhbnVwX2RvbWFpbnM6DQo+ICsJc2Nwc3lzX2Rv bWFpbl9jbGVhbnVwKHNjcHN5cyk7DQo+ICsJcmV0dXJuIHJldDsNCj4gK30NCj4gKw0KPiArc3Rh dGljIHN0cnVjdCBwbGF0Zm9ybV9kcml2ZXIgc2Nwc3lzX3BtX2RvbWFpbl9kcml2ZXIgPSB7DQo+ ICsJLnByb2JlID0gc2Nwc3lzX3Byb2JlLA0KPiArCS5kcml2ZXIgPSB7DQo+ICsJCS5uYW1lID0g Im10ay1wb3dlci1jb250cm9sbGVyIiwNCj4gKwkJLnN1cHByZXNzX2JpbmRfYXR0cnMgPSB0cnVl LA0KPiArCQkub2ZfbWF0Y2hfdGFibGUgPSBzY3BzeXNfb2ZfbWF0Y2gsDQo+ICsJfSwNCj4gK307 DQo+ICtidWlsdGluX3BsYXRmb3JtX2RyaXZlcihzY3BzeXNfcG1fZG9tYWluX2RyaXZlcik7DQoN Cg==