From mboxrd@z Thu Jan 1 00:00:00 1970 From: Felipe Balbi Subject: Re: [PATCH v1 2/2] usb: dwc3: Add Qualcomm DWC3 glue driver Date: Tue, 13 Mar 2018 13:08:14 +0200 Message-ID: <878taw8c81.fsf@linux.intel.com> References: <1520937362-28777-1-git-send-email-mgautam@codeaurora.org> <1520937362-28777-2-git-send-email-mgautam@codeaurora.org> Mime-Version: 1.0 Content-Type: multipart/signed; boundary="=-=-="; micalg=pgp-sha512; protocol="application/pgp-signature" Return-path: In-Reply-To: <1520937362-28777-2-git-send-email-mgautam@codeaurora.org> Sender: linux-kernel-owner@vger.kernel.org To: Rob Herring , Andy Gross Cc: linux-arm-msm@vger.kernel.org, linux-usb@vger.kernel.org, Manu Gautam , Greg Kroah-Hartman , open list List-Id: linux-arm-msm@vger.kernel.org --=-=-= Content-Type: text/plain Content-Transfer-Encoding: quoted-printable Hi, +Andy Manu Gautam writes: > DWC3 controller on Qualcomm SOCs has a Qscratch wrapper. > Some of its uses are described below resulting in need to > have a separate glue driver instead of using dwc3-of-simple: > - It exposes register interface to override vbus-override > and lane0-pwr-present signals going to hardware. These > must be updated in peripheral mode for DWC3 if vbus lines > are not connected to hardware block. Otherwise RX termination > in SS mode or DP pull-up is not applied by device controller. right, core needs to know that VBUS is above 4.4V. Why wasn't this a problem when the original glue layer was first published? > - pwr_events_irq_stat support to ensure USB2 PHY is in L2 state > before glue driver can turn-off clocks and suspend PHY. Core manages PHY suspend automatically. Isn't that working for you? Why? > - Support for wakeup interrupts lines that are asserted whenever > there is any wakeup event on USB3 or USB2 bus. ok > - Support to replace pip3 clock going to DWC3 with utmi clock > for hardware configuration where SSPHY is not used with DWC3. Is that SW configurable? Really? In any case seems like this and SESSVLD valid should be handled using Hans' and Heikki's mux support. > Other than above hardware features in Qscratch wrapper there > are some limitations on QCOM SOCs that require special handling > of power management e.g. suspending PHY using GUSB2PHYCFG > register and ensuring PHY enters L2 before turning off clocks etc. > > Signed-off-by: Manu Gautam > --- > drivers/usb/dwc3/Kconfig | 11 + > drivers/usb/dwc3/Makefile | 1 + > drivers/usb/dwc3/dwc3-of-simple.c | 1 - > drivers/usb/dwc3/dwc3-qcom.c | 635 ++++++++++++++++++++++++++++++++= ++++++ > 4 files changed, 647 insertions(+), 1 deletion(-) > create mode 100644 drivers/usb/dwc3/dwc3-qcom.c > > diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig > index ab8c0e0..f5bb4f1 100644 > --- a/drivers/usb/dwc3/Kconfig > +++ b/drivers/usb/dwc3/Kconfig > @@ -106,4 +106,15 @@ config USB_DWC3_ST > inside (i.e. STiH407). > Say 'Y' or 'M' if you have one such device. >=20=20 > +config USB_DWC3_QCOM > + tristate "Qualcomm Platform" > + depends on ARCH_QCOM || COMPILE_TEST > + depends on OF > + default USB_DWC3 > + help > + Some Qualcomm SoCs use DesignWare Core IP for USB2/3 > + functionality. > + > + Say 'Y' or 'M' if you have one such device. > + > endif > diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile > index 7ac7250..c3ce697 100644 > --- a/drivers/usb/dwc3/Makefile > +++ b/drivers/usb/dwc3/Makefile > @@ -48,3 +48,4 @@ obj-$(CONFIG_USB_DWC3_PCI) +=3D dwc3-pci.o > obj-$(CONFIG_USB_DWC3_KEYSTONE) +=3D dwc3-keystone.o > obj-$(CONFIG_USB_DWC3_OF_SIMPLE) +=3D dwc3-of-simple.o > obj-$(CONFIG_USB_DWC3_ST) +=3D dwc3-st.o > +obj-$(CONFIG_USB_DWC3_QCOM) +=3D dwc3-qcom.o > diff --git a/drivers/usb/dwc3/dwc3-of-simple.c b/drivers/usb/dwc3/dwc3-of= -simple.c > index cb2ee96..0fd0e8e 100644 > --- a/drivers/usb/dwc3/dwc3-of-simple.c > +++ b/drivers/usb/dwc3/dwc3-of-simple.c > @@ -208,7 +208,6 @@ static int dwc3_of_simple_runtime_resume(struct devic= e *dev) > }; >=20=20 > static const struct of_device_id of_dwc3_simple_match[] =3D { > - { .compatible =3D "qcom,dwc3" }, > { .compatible =3D "rockchip,rk3399-dwc3" }, > { .compatible =3D "xlnx,zynqmp-dwc3" }, > { .compatible =3D "cavium,octeon-7130-usb-uctl" }, > diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c > new file mode 100644 > index 0000000..917199e > --- /dev/null > +++ b/drivers/usb/dwc3/dwc3-qcom.c > @@ -0,0 +1,635 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. > + * > + * Inspired by dwc3-of-simple.c > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "core.h" > +#include "io.h" you must be kidding, right? There's no way I'm gonna let a glue poke at core registers. > +static void dwc3_qcom_suspend_hsphy(struct dwc3_qcom *qcom) > +{ > + struct dwc3 *dwc =3D platform_get_drvdata(qcom->dwc3); > + int ret; > + u32 val; > + > + /* Clear previous L2 events */ > + dwc3_qcom_setbits(qcom->qscratch_base, PWR_EVNT_IRQ_STAT_REG, > + PWR_EVNT_LPM_IN_L2_MASK | PWR_EVNT_LPM_OUT_L2_MASK); > + > + /* Allow controller to suspend HSPHY */ > + val =3D dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); > + val |=3D DWC3_GUSB2PHYCFG_ENBLSLPM | DWC3_GUSB2PHYCFG_SUSPHY; > + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), val); core should handle PHY bits. In any case, why don't you let core handle PHY suspend? It handles it automatically for us, there should be no need for SW intervention. > +static int dwc3_qcom_suspend(struct dwc3_qcom *qcom) > +{ > + struct dwc3 *dwc =3D platform_get_drvdata(qcom->dwc3); nope! Glue shouldn't touch dwc3 at all. > + int i; > + > + if (qcom->is_suspended) > + return 0; > + > + if (!dwc) > + return -EBUSY; =2DENODEV? > + dwc3_qcom_suspend_hsphy(qcom); > + > + if (dwc->usb2_generic_phy) > + phy_pm_runtime_put_sync(dwc->usb2_generic_phy); > + if (dwc->usb3_generic_phy) > + phy_pm_runtime_put_sync(dwc->usb3_generic_phy); core.c should do this. > + /* Disable HSPHY auto suspend */ > + val =3D dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); > + val &=3D ~(DWC3_GUSB2PHYCFG_ENBLSLPM | DWC3_GUSB2PHYCFG_SUSPHY); > + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), val); > + > + qcom->is_suspended =3D false; > + > + dev_dbg(qcom->dev, "DWC3 exited from low power mode\n"); no dev_dbg() or dev_info() in this driver. > +static irqreturn_t qcom_dwc3_resume_irq(int irq, void *data) > +{ > + struct dwc3_qcom *qcom =3D data; > + struct dwc3 *dwc =3D platform_get_drvdata(qcom->dwc3); > + > + /* If pm_suspended then let pm_resume take care of resuming h/w */ > + if (qcom->pm_suspended) > + return IRQ_HANDLED; > + > + dwc3_qcom_resume(qcom); instead, why don't you pm_runtime_resume() here, and let runtime_resume() handle dwc3_qcom_resume() ? > +static int dwc3_qcom_clk_init(struct dwc3_qcom *qcom, int count) > +{ > + struct device *dev =3D qcom->dev; > + struct device_node *np =3D dev->of_node; > + int i; > + > + qcom->num_clocks =3D count; > + > + if (!count) > + return 0; > + > + qcom->clks =3D devm_kcalloc(dev, qcom->num_clocks, > + sizeof(struct clk *), GFP_KERNEL); > + if (!qcom->clks) > + return -ENOMEM; > + > + for (i =3D 0; i < qcom->num_clocks; i++) { > + struct clk *clk; > + int ret; > + > + clk =3D of_clk_get(np, i); > + if (IS_ERR(clk)) { > + while (--i >=3D 0) > + clk_put(qcom->clks[i]); > + return PTR_ERR(clk); > + } > + > + ret =3D clk_prepare_enable(clk); > + if (ret < 0) { > + while (--i >=3D 0) { > + clk_disable_unprepare(qcom->clks[i]); > + clk_put(qcom->clks[i]); > + } > + clk_put(clk); > + > + return ret; > + } > + > + qcom->clks[i] =3D clk; > + } > + > + return 0; > +} > + > +static int dwc3_qcom_probe(struct platform_device *pdev) > +{ > + struct device_node *np =3D pdev->dev.of_node, *dwc3_np; > + struct dwc3_qcom *qcom; > + struct resource *res; > + int irq, ret, i; > + bool ignore_pipe_clk; > + > + qcom =3D devm_kzalloc(&pdev->dev, sizeof(*qcom), GFP_KERNEL); > + if (!qcom) > + return -ENOMEM; > + > + platform_set_drvdata(pdev, qcom); > + qcom->dev =3D &pdev->dev; > + > + qcom->resets =3D of_reset_control_array_get_optional_exclusive(np); > + if (IS_ERR(qcom->resets)) { > + ret =3D PTR_ERR(qcom->resets); > + dev_err(&pdev->dev, "failed to get resets, err=3D%d\n", ret); > + return ret; > + } > + > + ret =3D reset_control_deassert(qcom->resets); > + if (ret) > + goto reset_put; > + > + ret =3D dwc3_qcom_clk_init(qcom, of_clk_get_parent_count(np)); > + if (ret) { > + dev_err(qcom->dev, "failed to get clocks\n"); > + goto reset_assert; > + } > + > + res =3D platform_get_resource_byname(pdev, IORESOURCE_MEM, "qscratch"); > + qcom->qscratch_base =3D devm_ioremap_resource(qcom->dev, res); > + if (IS_ERR(qcom->qscratch_base)) { > + dev_err(qcom->dev, "failed to map qscratch - %d\n", ret); > + ret =3D PTR_ERR(qcom->qscratch_base); > + goto clk_disable; > + } > + > + irq =3D platform_get_irq_byname(pdev, "hs_phy_irq"); > + if (irq > 0) { > + ret =3D devm_request_threaded_irq(qcom->dev, irq, NULL, > + qcom_dwc3_resume_irq, > + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, > + "qcom_dwc3 HS", qcom); > + if (ret) { > + dev_err(qcom->dev, "hs_phy_irq failed: %d\n", ret); > + goto clk_disable; > + } > + } > + > + irq =3D platform_get_irq_byname(pdev, "dp_hs_phy_irq"); > + if (irq > 0) { > + irq_set_status_flags(irq, IRQ_NOAUTOEN); why do you need to set this flag? > + ret =3D devm_request_threaded_irq(qcom->dev, irq, NULL, > + qcom_dwc3_resume_irq, > + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, > + "qcom_dwc3 DP_HS", qcom); this is the same as devm_request_irq() > + if (ret) { > + dev_err(qcom->dev, "dp_hs_phy_irq failed: %d\n", ret); > + goto clk_disable; > + } > + qcom->dp_hs_phy_irq =3D irq; > + } > + > + irq =3D platform_get_irq_byname(pdev, "dm_hs_phy_irq"); > + if (irq > 0) { > + irq_set_status_flags(irq, IRQ_NOAUTOEN); > + ret =3D devm_request_threaded_irq(qcom->dev, irq, NULL, > + qcom_dwc3_resume_irq, > + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, > + "qcom_dwc3 DM_HS", qcom); > + if (ret) { > + dev_err(qcom->dev, "dm_hs_phy_irq failed: %d\n", ret); > + goto clk_disable; > + } > + qcom->dm_hs_phy_irq =3D irq; > + } > + > + irq =3D platform_get_irq_byname(pdev, "ss_phy_irq"); > + if (irq > 0) { > + irq_set_status_flags(irq, IRQ_NOAUTOEN); > + ret =3D devm_request_threaded_irq(qcom->dev, irq, NULL, > + qcom_dwc3_resume_irq, > + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, > + "qcom_dwc3 SS", qcom); > + if (ret) { > + dev_err(qcom->dev, "ss_phy_irq failed: %d\n", ret); > + goto clk_disable; > + } > + qcom->ss_phy_irq =3D irq; > + } > + > + dwc3_np =3D of_get_child_by_name(np, "dwc3"); > + if (!dwc3_np) { > + dev_err(qcom->dev, "failed to find dwc3 core child\n"); > + ret =3D -ENODEV; > + goto clk_disable; > + } > + > + /* > + * Disable pipe_clk requirement if specified. Used when dwc3 > + * operates without SSPHY and only HS/FS/LS modes are supported. > + */ > + ignore_pipe_clk =3D device_property_read_bool(qcom->dev, > + "qcom,select-utmi-as-pipe-clk"); > + if (ignore_pipe_clk) > + dwc3_qcom_select_utmi_clk(qcom); > + > + ret =3D of_platform_populate(np, NULL, NULL, qcom->dev); > + if (ret) { > + dev_err(qcom->dev, "failed to register dwc3 core - %d\n", ret); > + goto clk_disable; > + } > + > + qcom->dwc3 =3D of_find_device_by_node(dwc3_np); > + if (!qcom->dwc3) { > + dev_err(&pdev->dev, "failed to get dwc3 platform device\n"); > + goto depopulate; > + } > + > + qcom->mode =3D usb_get_dr_mode(&qcom->dwc3->dev); > + > + /* register extcon to override vbus later on mode switch */ > + if (qcom->mode =3D=3D USB_DR_MODE_OTG) { > + ret =3D dwc3_qcom_register_extcon(qcom); > + if (ret) > + goto depopulate; > + } else if (qcom->mode =3D=3D USB_DR_MODE_PERIPHERAL) { > + /* enable vbus override for device mode */ > + dwc3_qcom_vbus_overrride_enable(qcom, true); > + } > + > + device_init_wakeup(&pdev->dev, 1); > + qcom->is_suspended =3D false; > + pm_runtime_set_active(qcom->dev); > + pm_runtime_enable(qcom->dev); > + > + return 0; > + > +depopulate: > + of_platform_depopulate(&pdev->dev); > +clk_disable: > + for (i =3D qcom->num_clocks - 1; i >=3D 0; i--) { > + clk_disable_unprepare(qcom->clks[i]); > + clk_put(qcom->clks[i]); > + } > +reset_assert: > + reset_control_assert(qcom->resets); > +reset_put: > + reset_control_put(qcom->resets); > + > + return ret; > +} > + > +static int dwc3_qcom_remove(struct platform_device *pdev) > +{ > + struct dwc3_qcom *qcom =3D platform_get_drvdata(pdev); > + struct device *dev =3D qcom->dev; > + int i; > + > + of_platform_depopulate(&pdev->dev); > + > + for (i =3D qcom->num_clocks - 1; i >=3D 0; i--) { > + clk_disable_unprepare(qcom->clks[i]); > + clk_put(qcom->clks[i]); > + } > + qcom->num_clocks =3D 0; > + > + reset_control_assert(qcom->resets); > + reset_control_put(qcom->resets); > + > + pm_runtime_disable(dev); > + > + return 0; > +} > + > +#ifdef CONFIG_PM_SLEEP > +static int dwc3_qcom_pm_suspend(struct device *dev) > +{ > + struct dwc3_qcom *qcom =3D dev_get_drvdata(dev); > + int ret =3D 0; > + > + dev_err(dev, "dwc3-qcom PM suspend\n"); why an error message here? There's no error. Remove this, it's unnecessary. > + ret =3D dwc3_qcom_suspend(qcom); > + if (!ret) > + qcom->pm_suspended =3D true; > + > + return ret; > +} > + > +static int dwc3_qcom_pm_resume(struct device *dev) > +{ > + struct dwc3_qcom *qcom =3D dev_get_drvdata(dev); > + int ret; > + > + dev_err(dev, "dwc3-qcom PM resume\n"); ditto > + ret =3D dwc3_qcom_resume(qcom); > + if (!ret) > + qcom->pm_suspended =3D false; > + > + return ret; > +} > +#endif > + > +#ifdef CONFIG_PM > +static int dwc3_qcom_runtime_suspend(struct device *dev) > +{ > + struct dwc3_qcom *qcom =3D dev_get_drvdata(dev); > + > + dev_err(dev, "DWC3-qcom runtime suspend\n"); ditto > + return dwc3_qcom_suspend(qcom); > +} > + > +static int dwc3_qcom_runtime_resume(struct device *dev) > +{ > + struct dwc3_qcom *qcom =3D dev_get_drvdata(dev); > + > + dev_err(dev, "DWC3-qcom runtime resume\n"); ditto > + return dwc3_qcom_resume(qcom); > +} > +#endif > + > +static const struct dev_pm_ops dwc3_qcom_dev_pm_ops =3D { > + SET_SYSTEM_SLEEP_PM_OPS(dwc3_qcom_pm_suspend, dwc3_qcom_pm_resume) > + SET_RUNTIME_PM_OPS(dwc3_qcom_runtime_suspend, dwc3_qcom_runtime_resume, > + NULL) why don't you have runtime_idle? =2D-=20 balbi --=-=-= Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- iQIzBAEBCgAdFiEElLzh7wn96CXwjh2IzL64meEamQYFAlqnsR4ACgkQzL64meEa mQaM2hAAtpcjjx2FtDuNsiIx7EMT84EnJjt6o60odgNAvg3GwaxFMR405mpskyUf EbBSAuMI3CGQyBjB/zHigZdco5KTpVnFMu5ksFaAcZVP1JGmqWsGN6JVOkk9KEv9 42HZhawXDOzzc7BlJ1scoegomjx/sByIGfHtLFHGeG3idexSEKbd8oUG87mwwBM2 ldT5RNwKb+VLyIdCssdnbbJoZ0ZXC7ESXMfQ4DbSGzWaD0KTKXHCOh/cJdceuAJq TjC7c1YDQFbTJDSoepk4LkH3h90xEpPVtTokh5pz9MMRmyZDer7AkVW51uzKNi9b J6uRCPmvPjX+CkHtbS7L/vVOEowQy7TxwPA+ZMKyYvdxzrJx/KSCbe3Irx8tSB0E Lkkre3a9/rhtrBvQ5MW5jvkh00Hv1JPxjVh99ZZBUQ0Zb7mPWZYA3j7eSDGofMOz NZml3hi05jGqtrXqQduHU0UwcXQbfbBQY+VThYOyaKlG8cBV8t4fISJXaaAP/2lO C/cBnXAKokmKkOL9+p0YRVUp67KLJZNtoEbvvUjX/sA/MSTW9Y0OPBFganTJTXZ/ UlK5W7AJ7UIvlx0rPipiPmam0AyE1uSgaVWPzfWJeaY5Hu9aHKWiC4PnnZ576viP lo6Z65BK6wEBlvfmA1zdC9rcPQtsqsuLuxnu7t6KIU0l/Kc8UZY= =LJgf -----END PGP SIGNATURE----- --=-=-=-- From mboxrd@z Thu Jan 1 00:00:00 1970 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: base64 Subject: [v1,2/2] usb: dwc3: Add Qualcomm DWC3 glue driver From: Felipe Balbi Message-Id: <878taw8c81.fsf@linux.intel.com> Date: Tue, 13 Mar 2018 13:08:14 +0200 To: Manu Gautam , Rob Herring , Andy Gross Cc: linux-arm-msm@vger.kernel.org, linux-usb@vger.kernel.org, Greg Kroah-Hartman , open list List-ID: SGksCgorQW5keQoKTWFudSBHYXV0YW0gPG1nYXV0YW1AY29kZWF1cm9yYS5vcmc+IHdyaXRlczoK PiBEV0MzIGNvbnRyb2xsZXIgb24gUXVhbGNvbW0gU09DcyBoYXMgYSBRc2NyYXRjaCB3cmFwcGVy Lgo+IFNvbWUgb2YgaXRzIHVzZXMgYXJlIGRlc2NyaWJlZCBiZWxvdyByZXN1bHRpbmcgaW4gbmVl ZCB0bwo+IGhhdmUgYSBzZXBhcmF0ZSBnbHVlIGRyaXZlciBpbnN0ZWFkIG9mIHVzaW5nIGR3YzMt b2Ytc2ltcGxlOgo+ICAtIEl0IGV4cG9zZXMgcmVnaXN0ZXIgaW50ZXJmYWNlIHRvIG92ZXJyaWRl IHZidXMtb3ZlcnJpZGUKPiAgICBhbmQgbGFuZTAtcHdyLXByZXNlbnQgc2lnbmFscyBnb2luZyB0 byBoYXJkd2FyZS4gVGhlc2UKPiAgICBtdXN0IGJlIHVwZGF0ZWQgaW4gcGVyaXBoZXJhbCBtb2Rl IGZvciBEV0MzIGlmIHZidXMgbGluZXMKPiAgICBhcmUgbm90IGNvbm5lY3RlZCB0byBoYXJkd2Fy ZSBibG9jay4gT3RoZXJ3aXNlIFJYIHRlcm1pbmF0aW9uCj4gICAgaW4gU1MgbW9kZSBvciBEUCBw dWxsLXVwIGlzIG5vdCBhcHBsaWVkIGJ5IGRldmljZSBjb250cm9sbGVyLgoKcmlnaHQsIGNvcmUg bmVlZHMgdG8ga25vdyB0aGF0IFZCVVMgaXMgYWJvdmUgNC40Vi4gV2h5IHdhc24ndCB0aGlzIGEK cHJvYmxlbSB3aGVuIHRoZSBvcmlnaW5hbCBnbHVlIGxheWVyIHdhcyBmaXJzdCBwdWJsaXNoZWQ/ Cgo+ICAtIHB3cl9ldmVudHNfaXJxX3N0YXQgc3VwcG9ydCB0byBlbnN1cmUgVVNCMiBQSFkgaXMg aW4gTDIgc3RhdGUKPiAgICBiZWZvcmUgZ2x1ZSBkcml2ZXIgY2FuIHR1cm4tb2ZmIGNsb2NrcyBh bmQgc3VzcGVuZCBQSFkuCgpDb3JlIG1hbmFnZXMgUEhZIHN1c3BlbmQgYXV0b21hdGljYWxseS4g SXNuJ3QgdGhhdCB3b3JraW5nIGZvciB5b3U/IFdoeT8KCj4gIC0gU3VwcG9ydCBmb3Igd2FrZXVw IGludGVycnVwdHMgbGluZXMgdGhhdCBhcmUgYXNzZXJ0ZWQgd2hlbmV2ZXIKPiAgICB0aGVyZSBp cyBhbnkgd2FrZXVwIGV2ZW50IG9uIFVTQjMgb3IgVVNCMiBidXMuCgpvawoKPiAgLSBTdXBwb3J0 IHRvIHJlcGxhY2UgcGlwMyBjbG9jayBnb2luZyB0byBEV0MzIHdpdGggdXRtaSBjbG9jawo+ICAg IGZvciBoYXJkd2FyZSBjb25maWd1cmF0aW9uIHdoZXJlIFNTUEhZIGlzIG5vdCB1c2VkIHdpdGgg RFdDMy4KCklzIHRoYXQgU1cgY29uZmlndXJhYmxlPyBSZWFsbHk/IEluIGFueSBjYXNlIHNlZW1z IGxpa2UgdGhpcyBhbmQgU0VTU1ZMRAp2YWxpZCBzaG91bGQgYmUgaGFuZGxlZCB1c2luZyBIYW5z JyBhbmQgSGVpa2tpJ3MgbXV4IHN1cHBvcnQuCgo+IE90aGVyIHRoYW4gYWJvdmUgaGFyZHdhcmUg ZmVhdHVyZXMgaW4gUXNjcmF0Y2ggd3JhcHBlciB0aGVyZQo+IGFyZSBzb21lIGxpbWl0YXRpb25z IG9uIFFDT00gU09DcyB0aGF0IHJlcXVpcmUgc3BlY2lhbCBoYW5kbGluZwo+IG9mIHBvd2VyIG1h bmFnZW1lbnQgZS5nLiBzdXNwZW5kaW5nIFBIWSB1c2luZyBHVVNCMlBIWUNGRwo+IHJlZ2lzdGVy IGFuZCBlbnN1cmluZyBQSFkgZW50ZXJzIEwyIGJlZm9yZSB0dXJuaW5nIG9mZiBjbG9ja3MgZXRj Lgo+Cj4gU2lnbmVkLW9mZi1ieTogTWFudSBHYXV0YW0gPG1nYXV0YW1AY29kZWF1cm9yYS5vcmc+ Cj4gLS0tCj4gIGRyaXZlcnMvdXNiL2R3YzMvS2NvbmZpZyAgICAgICAgICB8ICAxMSArCj4gIGRy aXZlcnMvdXNiL2R3YzMvTWFrZWZpbGUgICAgICAgICB8ICAgMSArCj4gIGRyaXZlcnMvdXNiL2R3 YzMvZHdjMy1vZi1zaW1wbGUuYyB8ICAgMSAtCj4gIGRyaXZlcnMvdXNiL2R3YzMvZHdjMy1xY29t LmMgICAgICB8IDYzNSArKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKwo+ICA0 IGZpbGVzIGNoYW5nZWQsIDY0NyBpbnNlcnRpb25zKCspLCAxIGRlbGV0aW9uKC0pCj4gIGNyZWF0 ZSBtb2RlIDEwMDY0NCBkcml2ZXJzL3VzYi9kd2MzL2R3YzMtcWNvbS5jCj4KPiBkaWZmIC0tZ2l0 IGEvZHJpdmVycy91c2IvZHdjMy9LY29uZmlnIGIvZHJpdmVycy91c2IvZHdjMy9LY29uZmlnCj4g aW5kZXggYWI4YzBlMC4uZjViYjRmMSAxMDA2NDQKPiAtLS0gYS9kcml2ZXJzL3VzYi9kd2MzL0tj b25maWcKPiArKysgYi9kcml2ZXJzL3VzYi9kd2MzL0tjb25maWcKPiBAQCAtMTA2LDQgKzEwNiwx NSBAQCBjb25maWcgVVNCX0RXQzNfU1QKPiAgCSAgaW5zaWRlIChpLmUuIFNUaUg0MDcpLgo+ICAJ ICBTYXkgJ1knIG9yICdNJyBpZiB5b3UgaGF2ZSBvbmUgc3VjaCBkZXZpY2UuCj4gIAo+ICtjb25m aWcgVVNCX0RXQzNfUUNPTQo+ICsJdHJpc3RhdGUgIlF1YWxjb21tIFBsYXRmb3JtIgo+ICsJZGVw ZW5kcyBvbiBBUkNIX1FDT00gfHwgQ09NUElMRV9URVNUCj4gKwlkZXBlbmRzIG9uIE9GCj4gKwlk ZWZhdWx0IFVTQl9EV0MzCj4gKwloZWxwCj4gKwkgIFNvbWUgUXVhbGNvbW0gU29DcyB1c2UgRGVz aWduV2FyZSBDb3JlIElQIGZvciBVU0IyLzMKPiArCSAgZnVuY3Rpb25hbGl0eS4KPiArCj4gKwkg IFNheSAnWScgb3IgJ00nIGlmIHlvdSBoYXZlIG9uZSBzdWNoIGRldmljZS4KPiArCj4gIGVuZGlm Cj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvdXNiL2R3YzMvTWFrZWZpbGUgYi9kcml2ZXJzL3VzYi9k d2MzL01ha2VmaWxlCj4gaW5kZXggN2FjNzI1MC4uYzNjZTY5NyAxMDA2NDQKPiAtLS0gYS9kcml2 ZXJzL3VzYi9kd2MzL01ha2VmaWxlCj4gKysrIGIvZHJpdmVycy91c2IvZHdjMy9NYWtlZmlsZQo+ IEBAIC00OCwzICs0OCw0IEBAIG9iai0kKENPTkZJR19VU0JfRFdDM19QQ0kpCQkrPSBkd2MzLXBj aS5vCj4gIG9iai0kKENPTkZJR19VU0JfRFdDM19LRVlTVE9ORSkJCSs9IGR3YzMta2V5c3RvbmUu bwo+ICBvYmotJChDT05GSUdfVVNCX0RXQzNfT0ZfU0lNUExFKQkrPSBkd2MzLW9mLXNpbXBsZS5v Cj4gIG9iai0kKENPTkZJR19VU0JfRFdDM19TVCkJCSs9IGR3YzMtc3Qubwo+ICtvYmotJChDT05G SUdfVVNCX0RXQzNfUUNPTSkJCSs9IGR3YzMtcWNvbS5vCj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMv dXNiL2R3YzMvZHdjMy1vZi1zaW1wbGUuYyBiL2RyaXZlcnMvdXNiL2R3YzMvZHdjMy1vZi1zaW1w bGUuYwo+IGluZGV4IGNiMmVlOTYuLjBmZDBlOGUgMTAwNjQ0Cj4gLS0tIGEvZHJpdmVycy91c2Iv ZHdjMy9kd2MzLW9mLXNpbXBsZS5jCj4gKysrIGIvZHJpdmVycy91c2IvZHdjMy9kd2MzLW9mLXNp bXBsZS5jCj4gQEAgLTIwOCw3ICsyMDgsNiBAQCBzdGF0aWMgaW50IGR3YzNfb2Zfc2ltcGxlX3J1 bnRpbWVfcmVzdW1lKHN0cnVjdCBkZXZpY2UgKmRldikKPiAgfTsKPiAgCj4gIHN0YXRpYyBjb25z dCBzdHJ1Y3Qgb2ZfZGV2aWNlX2lkIG9mX2R3YzNfc2ltcGxlX21hdGNoW10gPSB7Cj4gLQl7IC5j b21wYXRpYmxlID0gInFjb20sZHdjMyIgfSwKPiAgCXsgLmNvbXBhdGlibGUgPSAicm9ja2NoaXAs cmszMzk5LWR3YzMiIH0sCj4gIAl7IC5jb21wYXRpYmxlID0gInhsbngsenlucW1wLWR3YzMiIH0s Cj4gIAl7IC5jb21wYXRpYmxlID0gImNhdml1bSxvY3Rlb24tNzEzMC11c2ItdWN0bCIgfSwKPiBk aWZmIC0tZ2l0IGEvZHJpdmVycy91c2IvZHdjMy9kd2MzLXFjb20uYyBiL2RyaXZlcnMvdXNiL2R3 YzMvZHdjMy1xY29tLmMKPiBuZXcgZmlsZSBtb2RlIDEwMDY0NAo+IGluZGV4IDAwMDAwMDAuLjkx NzE5OWUKPiAtLS0gL2Rldi9udWxsCj4gKysrIGIvZHJpdmVycy91c2IvZHdjMy9kd2MzLXFjb20u Ywo+IEBAIC0wLDAgKzEsNjM1IEBACj4gKy8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBHUEwt Mi4wCj4gKy8qIENvcHlyaWdodCAoYykgMjAxOCwgVGhlIExpbnV4IEZvdW5kYXRpb24uIEFsbCBy aWdodHMgcmVzZXJ2ZWQuCj4gKyAqCj4gKyAqIEluc3BpcmVkIGJ5IGR3YzMtb2Ytc2ltcGxlLmMK PiArICovCj4gKwo+ICsjaW5jbHVkZSA8bGludXgvaW8uaD4KPiArI2luY2x1ZGUgPGxpbnV4L29m Lmg+Cj4gKyNpbmNsdWRlIDxsaW51eC9jbGsuaD4KPiArI2luY2x1ZGUgPGxpbnV4L2lycS5oPgo+ ICsjaW5jbHVkZSA8bGludXgvY2xrLXByb3ZpZGVyLmg+Cj4gKyNpbmNsdWRlIDxsaW51eC9tb2R1 bGUuaD4KPiArI2luY2x1ZGUgPGxpbnV4L2tlcm5lbC5oPgo+ICsjaW5jbHVkZSA8bGludXgvZXh0 Y29uLmg+Cj4gKyNpbmNsdWRlIDxsaW51eC9vZl9wbGF0Zm9ybS5oPgo+ICsjaW5jbHVkZSA8bGlu dXgvcGxhdGZvcm1fZGV2aWNlLmg+Cj4gKyNpbmNsdWRlIDxsaW51eC9waHkvcGh5Lmg+Cj4gKyNp bmNsdWRlIDxsaW51eC91c2Ivb2YuaD4KPiArI2luY2x1ZGUgPGxpbnV4L3Jlc2V0Lmg+Cj4gKyNp bmNsdWRlIDxsaW51eC9pb3BvbGwuaD4KPiArCj4gKyNpbmNsdWRlICJjb3JlLmgiCj4gKyNpbmNs dWRlICJpby5oIgoKeW91IG11c3QgYmUga2lkZGluZywgcmlnaHQ/IFRoZXJlJ3Mgbm8gd2F5IEkn bSBnb25uYSBsZXQgYSBnbHVlIHBva2UgYXQKY29yZSByZWdpc3RlcnMuCgo+ICtzdGF0aWMgdm9p ZCBkd2MzX3Fjb21fc3VzcGVuZF9oc3BoeShzdHJ1Y3QgZHdjM19xY29tICpxY29tKQo+ICt7Cj4g KwlzdHJ1Y3QgZHdjMwkqZHdjID0gcGxhdGZvcm1fZ2V0X2RydmRhdGEocWNvbS0+ZHdjMyk7Cj4g KwlpbnQJCXJldDsKPiArCXUzMgkJdmFsOwo+ICsKPiArCS8qIENsZWFyIHByZXZpb3VzIEwyIGV2 ZW50cyAqLwo+ICsJZHdjM19xY29tX3NldGJpdHMocWNvbS0+cXNjcmF0Y2hfYmFzZSwgUFdSX0VW TlRfSVJRX1NUQVRfUkVHLAo+ICsJCQkgIFBXUl9FVk5UX0xQTV9JTl9MMl9NQVNLIHwgUFdSX0VW TlRfTFBNX09VVF9MMl9NQVNLKTsKPiArCj4gKwkvKiBBbGxvdyBjb250cm9sbGVyIHRvIHN1c3Bl bmQgSFNQSFkgKi8KPiArCXZhbCA9IGR3YzNfcmVhZGwoZHdjLT5yZWdzLCBEV0MzX0dVU0IyUEhZ Q0ZHKDApKTsKPiArCXZhbCB8PSAgRFdDM19HVVNCMlBIWUNGR19FTkJMU0xQTSB8IERXQzNfR1VT QjJQSFlDRkdfU1VTUEhZOwo+ICsJZHdjM193cml0ZWwoZHdjLT5yZWdzLCBEV0MzX0dVU0IyUEhZ Q0ZHKDApLCB2YWwpOwoKY29yZSBzaG91bGQgaGFuZGxlIFBIWSBiaXRzLiBJbiBhbnkgY2FzZSwg d2h5IGRvbid0IHlvdSBsZXQgY29yZSBoYW5kbGUKUEhZIHN1c3BlbmQ/IEl0IGhhbmRsZXMgaXQg YXV0b21hdGljYWxseSBmb3IgdXMsIHRoZXJlIHNob3VsZCBiZSBubyBuZWVkCmZvciBTVyBpbnRl cnZlbnRpb24uCgo+ICtzdGF0aWMgaW50IGR3YzNfcWNvbV9zdXNwZW5kKHN0cnVjdCBkd2MzX3Fj b20gKnFjb20pCj4gK3sKPiArCXN0cnVjdCBkd2MzCSpkd2MgPSBwbGF0Zm9ybV9nZXRfZHJ2ZGF0 YShxY29tLT5kd2MzKTsKCm5vcGUhIEdsdWUgc2hvdWxkbid0IHRvdWNoIGR3YzMgYXQgYWxsLgoK PiArCWludAkJIGk7Cj4gKwo+ICsJaWYgKHFjb20tPmlzX3N1c3BlbmRlZCkKPiArCQlyZXR1cm4g MDsKPiArCj4gKwlpZiAoIWR3YykKPiArCQlyZXR1cm4gLUVCVVNZOwoKLUVOT0RFVj8KCj4gKwlk d2MzX3Fjb21fc3VzcGVuZF9oc3BoeShxY29tKTsKPiArCj4gKwlpZiAoZHdjLT51c2IyX2dlbmVy aWNfcGh5KQo+ICsJCXBoeV9wbV9ydW50aW1lX3B1dF9zeW5jKGR3Yy0+dXNiMl9nZW5lcmljX3Bo eSk7Cj4gKwlpZiAoZHdjLT51c2IzX2dlbmVyaWNfcGh5KQo+ICsJCXBoeV9wbV9ydW50aW1lX3B1 dF9zeW5jKGR3Yy0+dXNiM19nZW5lcmljX3BoeSk7Cgpjb3JlLmMgc2hvdWxkIGRvIHRoaXMuCgo+ ICsJLyogRGlzYWJsZSBIU1BIWSBhdXRvIHN1c3BlbmQgKi8KPiArCXZhbCA9IGR3YzNfcmVhZGwo ZHdjLT5yZWdzLCBEV0MzX0dVU0IyUEhZQ0ZHKDApKTsKPiArCXZhbCAmPSB+KERXQzNfR1VTQjJQ SFlDRkdfRU5CTFNMUE0gfCBEV0MzX0dVU0IyUEhZQ0ZHX1NVU1BIWSk7Cj4gKwlkd2MzX3dyaXRl bChkd2MtPnJlZ3MsIERXQzNfR1VTQjJQSFlDRkcoMCksIHZhbCk7Cj4gKwo+ICsJcWNvbS0+aXNf c3VzcGVuZGVkID0gZmFsc2U7Cj4gKwo+ICsJZGV2X2RiZyhxY29tLT5kZXYsICJEV0MzIGV4aXRl ZCBmcm9tIGxvdyBwb3dlciBtb2RlXG4iKTsKCm5vIGRldl9kYmcoKSBvciBkZXZfaW5mbygpIGlu IHRoaXMgZHJpdmVyLgoKPiArc3RhdGljIGlycXJldHVybl90IHFjb21fZHdjM19yZXN1bWVfaXJx KGludCBpcnEsIHZvaWQgKmRhdGEpCj4gK3sKPiArCXN0cnVjdCBkd2MzX3Fjb20gKnFjb20gPSBk YXRhOwo+ICsJc3RydWN0IGR3YzMJKmR3YyA9IHBsYXRmb3JtX2dldF9kcnZkYXRhKHFjb20tPmR3 YzMpOwo+ICsKPiArCS8qIElmIHBtX3N1c3BlbmRlZCB0aGVuIGxldCBwbV9yZXN1bWUgdGFrZSBj YXJlIG9mIHJlc3VtaW5nIGgvdyAqLwo+ICsJaWYgKHFjb20tPnBtX3N1c3BlbmRlZCkKPiArCQly ZXR1cm4gSVJRX0hBTkRMRUQ7Cj4gKwo+ICsJZHdjM19xY29tX3Jlc3VtZShxY29tKTsKCmluc3Rl YWQsIHdoeSBkb24ndCB5b3UgcG1fcnVudGltZV9yZXN1bWUoKSBoZXJlLCBhbmQgbGV0IHJ1bnRp bWVfcmVzdW1lKCkKaGFuZGxlIGR3YzNfcWNvbV9yZXN1bWUoKSA/Cgo+ICtzdGF0aWMgaW50IGR3 YzNfcWNvbV9jbGtfaW5pdChzdHJ1Y3QgZHdjM19xY29tICpxY29tLCBpbnQgY291bnQpCj4gK3sK PiArCXN0cnVjdCBkZXZpY2UJCSpkZXYgPSBxY29tLT5kZXY7Cj4gKwlzdHJ1Y3QgZGV2aWNlX25v ZGUJKm5wID0gZGV2LT5vZl9ub2RlOwo+ICsJaW50CQkJaTsKPiArCj4gKwlxY29tLT5udW1fY2xv Y2tzID0gY291bnQ7Cj4gKwo+ICsJaWYgKCFjb3VudCkKPiArCQlyZXR1cm4gMDsKPiArCj4gKwlx Y29tLT5jbGtzID0gZGV2bV9rY2FsbG9jKGRldiwgcWNvbS0+bnVtX2Nsb2NrcywKPiArCQkJCSAg c2l6ZW9mKHN0cnVjdCBjbGsgKiksIEdGUF9LRVJORUwpOwo+ICsJaWYgKCFxY29tLT5jbGtzKQo+ ICsJCXJldHVybiAtRU5PTUVNOwo+ICsKPiArCWZvciAoaSA9IDA7IGkgPCBxY29tLT5udW1fY2xv Y2tzOyBpKyspIHsKPiArCQlzdHJ1Y3QgY2xrCSpjbGs7Cj4gKwkJaW50CQlyZXQ7Cj4gKwo+ICsJ CWNsayA9IG9mX2Nsa19nZXQobnAsIGkpOwo+ICsJCWlmIChJU19FUlIoY2xrKSkgewo+ICsJCQl3 aGlsZSAoLS1pID49IDApCj4gKwkJCQljbGtfcHV0KHFjb20tPmNsa3NbaV0pOwo+ICsJCQlyZXR1 cm4gUFRSX0VSUihjbGspOwo+ICsJCX0KPiArCj4gKwkJcmV0ID0gY2xrX3ByZXBhcmVfZW5hYmxl KGNsayk7Cj4gKwkJaWYgKHJldCA8IDApIHsKPiArCQkJd2hpbGUgKC0taSA+PSAwKSB7Cj4gKwkJ CQljbGtfZGlzYWJsZV91bnByZXBhcmUocWNvbS0+Y2xrc1tpXSk7Cj4gKwkJCQljbGtfcHV0KHFj b20tPmNsa3NbaV0pOwo+ICsJCQl9Cj4gKwkJCWNsa19wdXQoY2xrKTsKPiArCj4gKwkJCXJldHVy biByZXQ7Cj4gKwkJfQo+ICsKPiArCQlxY29tLT5jbGtzW2ldID0gY2xrOwo+ICsJfQo+ICsKPiAr CXJldHVybiAwOwo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IGR3YzNfcWNvbV9wcm9iZShzdHJ1Y3Qg cGxhdGZvcm1fZGV2aWNlICpwZGV2KQo+ICt7Cj4gKwlzdHJ1Y3QgZGV2aWNlX25vZGUJKm5wID0g cGRldi0+ZGV2Lm9mX25vZGUsICpkd2MzX25wOwo+ICsJc3RydWN0IGR3YzNfcWNvbQkqcWNvbTsK PiArCXN0cnVjdCByZXNvdXJjZQkJKnJlczsKPiArCWludAkJCWlycSwgcmV0LCBpOwo+ICsJYm9v bAkJCWlnbm9yZV9waXBlX2NsazsKPiArCj4gKwlxY29tID0gZGV2bV9remFsbG9jKCZwZGV2LT5k ZXYsIHNpemVvZigqcWNvbSksIEdGUF9LRVJORUwpOwo+ICsJaWYgKCFxY29tKQo+ICsJCXJldHVy biAtRU5PTUVNOwo+ICsKPiArCXBsYXRmb3JtX3NldF9kcnZkYXRhKHBkZXYsIHFjb20pOwo+ICsJ cWNvbS0+ZGV2ID0gJnBkZXYtPmRldjsKPiArCj4gKwlxY29tLT5yZXNldHMgPSBvZl9yZXNldF9j b250cm9sX2FycmF5X2dldF9vcHRpb25hbF9leGNsdXNpdmUobnApOwo+ICsJaWYgKElTX0VSUihx Y29tLT5yZXNldHMpKSB7Cj4gKwkJcmV0ID0gUFRSX0VSUihxY29tLT5yZXNldHMpOwo+ICsJCWRl dl9lcnIoJnBkZXYtPmRldiwgImZhaWxlZCB0byBnZXQgcmVzZXRzLCBlcnI9JWRcbiIsIHJldCk7 Cj4gKwkJcmV0dXJuIHJldDsKPiArCX0KPiArCj4gKwlyZXQgPSByZXNldF9jb250cm9sX2RlYXNz ZXJ0KHFjb20tPnJlc2V0cyk7Cj4gKwlpZiAocmV0KQo+ICsJCWdvdG8gcmVzZXRfcHV0Owo+ICsK PiArCXJldCA9IGR3YzNfcWNvbV9jbGtfaW5pdChxY29tLCBvZl9jbGtfZ2V0X3BhcmVudF9jb3Vu dChucCkpOwo+ICsJaWYgKHJldCkgewo+ICsJCWRldl9lcnIocWNvbS0+ZGV2LCAiZmFpbGVkIHRv IGdldCBjbG9ja3NcbiIpOwo+ICsJCWdvdG8gcmVzZXRfYXNzZXJ0Owo+ICsJfQo+ICsKPiArCXJl cyA9IHBsYXRmb3JtX2dldF9yZXNvdXJjZV9ieW5hbWUocGRldiwgSU9SRVNPVVJDRV9NRU0sICJx c2NyYXRjaCIpOwo+ICsJcWNvbS0+cXNjcmF0Y2hfYmFzZSA9IGRldm1faW9yZW1hcF9yZXNvdXJj ZShxY29tLT5kZXYsIHJlcyk7Cj4gKwlpZiAoSVNfRVJSKHFjb20tPnFzY3JhdGNoX2Jhc2UpKSB7 Cj4gKwkJZGV2X2VycihxY29tLT5kZXYsICJmYWlsZWQgdG8gbWFwIHFzY3JhdGNoIC0gJWRcbiIs IHJldCk7Cj4gKwkJcmV0ID0gUFRSX0VSUihxY29tLT5xc2NyYXRjaF9iYXNlKTsKPiArCQlnb3Rv IGNsa19kaXNhYmxlOwo+ICsJfQo+ICsKPiArCWlycSA9IHBsYXRmb3JtX2dldF9pcnFfYnluYW1l KHBkZXYsICJoc19waHlfaXJxIik7Cj4gKwlpZiAoaXJxID4gMCkgewo+ICsJCXJldCA9IGRldm1f cmVxdWVzdF90aHJlYWRlZF9pcnEocWNvbS0+ZGV2LCBpcnEsIE5VTEwsCj4gKwkJCQkJcWNvbV9k d2MzX3Jlc3VtZV9pcnEsCj4gKwkJCQkJSVJRRl9UUklHR0VSX0hJR0ggfCBJUlFGX09ORVNIT1Qs Cj4gKwkJCQkJInFjb21fZHdjMyBIUyIsIHFjb20pOwo+ICsJCWlmIChyZXQpIHsKPiArCQkJZGV2 X2VycihxY29tLT5kZXYsICJoc19waHlfaXJxIGZhaWxlZDogJWRcbiIsIHJldCk7Cj4gKwkJCWdv dG8gY2xrX2Rpc2FibGU7Cj4gKwkJfQo+ICsJfQo+ICsKPiArCWlycSA9IHBsYXRmb3JtX2dldF9p cnFfYnluYW1lKHBkZXYsICJkcF9oc19waHlfaXJxIik7Cj4gKwlpZiAoaXJxID4gMCkgewo+ICsJ CWlycV9zZXRfc3RhdHVzX2ZsYWdzKGlycSwgSVJRX05PQVVUT0VOKTsKCndoeSBkbyB5b3UgbmVl ZCB0byBzZXQgdGhpcyBmbGFnPwoKPiArCQlyZXQgPSBkZXZtX3JlcXVlc3RfdGhyZWFkZWRfaXJx KHFjb20tPmRldiwgaXJxLCBOVUxMLAo+ICsJCQkJCXFjb21fZHdjM19yZXN1bWVfaXJxLAo+ICsJ CQkJCUlSUUZfVFJJR0dFUl9ISUdIIHwgSVJRRl9PTkVTSE9ULAo+ICsJCQkJCSJxY29tX2R3YzMg RFBfSFMiLCBxY29tKTsKCnRoaXMgaXMgdGhlIHNhbWUgYXMgZGV2bV9yZXF1ZXN0X2lycSgpCgo+ ICsJCWlmIChyZXQpIHsKPiArCQkJZGV2X2VycihxY29tLT5kZXYsICJkcF9oc19waHlfaXJxIGZh aWxlZDogJWRcbiIsIHJldCk7Cj4gKwkJCWdvdG8gY2xrX2Rpc2FibGU7Cj4gKwkJfQo+ICsJCXFj b20tPmRwX2hzX3BoeV9pcnEgPSBpcnE7Cj4gKwl9Cj4gKwo+ICsJaXJxID0gcGxhdGZvcm1fZ2V0 X2lycV9ieW5hbWUocGRldiwgImRtX2hzX3BoeV9pcnEiKTsKPiArCWlmIChpcnEgPiAwKSB7Cj4g KwkJaXJxX3NldF9zdGF0dXNfZmxhZ3MoaXJxLCBJUlFfTk9BVVRPRU4pOwo+ICsJCXJldCA9IGRl dm1fcmVxdWVzdF90aHJlYWRlZF9pcnEocWNvbS0+ZGV2LCBpcnEsIE5VTEwsCj4gKwkJCQkJcWNv bV9kd2MzX3Jlc3VtZV9pcnEsCj4gKwkJCQkJSVJRRl9UUklHR0VSX0hJR0ggfCBJUlFGX09ORVNI T1QsCj4gKwkJCQkJInFjb21fZHdjMyBETV9IUyIsIHFjb20pOwo+ICsJCWlmIChyZXQpIHsKPiAr CQkJZGV2X2VycihxY29tLT5kZXYsICJkbV9oc19waHlfaXJxIGZhaWxlZDogJWRcbiIsIHJldCk7 Cj4gKwkJCWdvdG8gY2xrX2Rpc2FibGU7Cj4gKwkJfQo+ICsJCXFjb20tPmRtX2hzX3BoeV9pcnEg PSBpcnE7Cj4gKwl9Cj4gKwo+ICsJaXJxID0gcGxhdGZvcm1fZ2V0X2lycV9ieW5hbWUocGRldiwg InNzX3BoeV9pcnEiKTsKPiArCWlmIChpcnEgPiAwKSB7Cj4gKwkJaXJxX3NldF9zdGF0dXNfZmxh Z3MoaXJxLCBJUlFfTk9BVVRPRU4pOwo+ICsJCXJldCA9IGRldm1fcmVxdWVzdF90aHJlYWRlZF9p cnEocWNvbS0+ZGV2LCBpcnEsIE5VTEwsCj4gKwkJCQkJcWNvbV9kd2MzX3Jlc3VtZV9pcnEsCj4g KwkJCQkJSVJRRl9UUklHR0VSX0hJR0ggfCBJUlFGX09ORVNIT1QsCj4gKwkJCQkJInFjb21fZHdj MyBTUyIsIHFjb20pOwo+ICsJCWlmIChyZXQpIHsKPiArCQkJZGV2X2VycihxY29tLT5kZXYsICJz c19waHlfaXJxIGZhaWxlZDogJWRcbiIsIHJldCk7Cj4gKwkJCWdvdG8gY2xrX2Rpc2FibGU7Cj4g KwkJfQo+ICsJCXFjb20tPnNzX3BoeV9pcnEgPSBpcnE7Cj4gKwl9Cj4gKwo+ICsJZHdjM19ucCA9 IG9mX2dldF9jaGlsZF9ieV9uYW1lKG5wLCAiZHdjMyIpOwo+ICsJaWYgKCFkd2MzX25wKSB7Cj4g KwkJZGV2X2VycihxY29tLT5kZXYsICJmYWlsZWQgdG8gZmluZCBkd2MzIGNvcmUgY2hpbGRcbiIp Owo+ICsJCXJldCA9IC1FTk9ERVY7Cj4gKwkJZ290byBjbGtfZGlzYWJsZTsKPiArCX0KPiArCj4g KwkvKgo+ICsJICogRGlzYWJsZSBwaXBlX2NsayByZXF1aXJlbWVudCBpZiBzcGVjaWZpZWQuIFVz ZWQgd2hlbiBkd2MzCj4gKwkgKiBvcGVyYXRlcyB3aXRob3V0IFNTUEhZIGFuZCBvbmx5IEhTL0ZT L0xTIG1vZGVzIGFyZSBzdXBwb3J0ZWQuCj4gKwkgKi8KPiArCWlnbm9yZV9waXBlX2NsayA9IGRl dmljZV9wcm9wZXJ0eV9yZWFkX2Jvb2wocWNvbS0+ZGV2LAo+ICsJCQkJInFjb20sc2VsZWN0LXV0 bWktYXMtcGlwZS1jbGsiKTsKPiArCWlmIChpZ25vcmVfcGlwZV9jbGspCj4gKwkJZHdjM19xY29t X3NlbGVjdF91dG1pX2NsayhxY29tKTsKPiArCj4gKwlyZXQgPSBvZl9wbGF0Zm9ybV9wb3B1bGF0 ZShucCwgTlVMTCwgTlVMTCwgcWNvbS0+ZGV2KTsKPiArCWlmIChyZXQpIHsKPiArCQlkZXZfZXJy KHFjb20tPmRldiwgImZhaWxlZCB0byByZWdpc3RlciBkd2MzIGNvcmUgLSAlZFxuIiwgcmV0KTsK PiArCQlnb3RvIGNsa19kaXNhYmxlOwo+ICsJfQo+ICsKPiArCXFjb20tPmR3YzMgPSBvZl9maW5k X2RldmljZV9ieV9ub2RlKGR3YzNfbnApOwo+ICsJaWYgKCFxY29tLT5kd2MzKSB7Cj4gKwkJZGV2 X2VycigmcGRldi0+ZGV2LCAiZmFpbGVkIHRvIGdldCBkd2MzIHBsYXRmb3JtIGRldmljZVxuIik7 Cj4gKwkJZ290byBkZXBvcHVsYXRlOwo+ICsJfQo+ICsKPiArCXFjb20tPm1vZGUgPSB1c2JfZ2V0 X2RyX21vZGUoJnFjb20tPmR3YzMtPmRldik7Cj4gKwo+ICsJLyogcmVnaXN0ZXIgZXh0Y29uIHRv IG92ZXJyaWRlIHZidXMgbGF0ZXIgb24gbW9kZSBzd2l0Y2ggKi8KPiArCWlmIChxY29tLT5tb2Rl ID09IFVTQl9EUl9NT0RFX09URykgewo+ICsJCXJldCA9IGR3YzNfcWNvbV9yZWdpc3Rlcl9leHRj b24ocWNvbSk7Cj4gKwkJaWYgKHJldCkKPiArCQkJZ290byBkZXBvcHVsYXRlOwo+ICsJfSBlbHNl IGlmIChxY29tLT5tb2RlID09IFVTQl9EUl9NT0RFX1BFUklQSEVSQUwpIHsKPiArCQkvKiBlbmFi bGUgdmJ1cyBvdmVycmlkZSBmb3IgZGV2aWNlIG1vZGUgKi8KPiArCQlkd2MzX3Fjb21fdmJ1c19v dmVycnJpZGVfZW5hYmxlKHFjb20sIHRydWUpOwo+ICsJfQo+ICsKPiArCWRldmljZV9pbml0X3dh a2V1cCgmcGRldi0+ZGV2LCAxKTsKPiArCXFjb20tPmlzX3N1c3BlbmRlZCA9IGZhbHNlOwo+ICsJ cG1fcnVudGltZV9zZXRfYWN0aXZlKHFjb20tPmRldik7Cj4gKwlwbV9ydW50aW1lX2VuYWJsZShx Y29tLT5kZXYpOwo+ICsKPiArCXJldHVybiAwOwo+ICsKPiArZGVwb3B1bGF0ZToKPiArCW9mX3Bs YXRmb3JtX2RlcG9wdWxhdGUoJnBkZXYtPmRldik7Cj4gK2Nsa19kaXNhYmxlOgo+ICsJZm9yIChp ID0gcWNvbS0+bnVtX2Nsb2NrcyAtIDE7IGkgPj0gMDsgaS0tKSB7Cj4gKwkJY2xrX2Rpc2FibGVf dW5wcmVwYXJlKHFjb20tPmNsa3NbaV0pOwo+ICsJCWNsa19wdXQocWNvbS0+Y2xrc1tpXSk7Cj4g Kwl9Cj4gK3Jlc2V0X2Fzc2VydDoKPiArCXJlc2V0X2NvbnRyb2xfYXNzZXJ0KHFjb20tPnJlc2V0 cyk7Cj4gK3Jlc2V0X3B1dDoKPiArCXJlc2V0X2NvbnRyb2xfcHV0KHFjb20tPnJlc2V0cyk7Cj4g Kwo+ICsJcmV0dXJuIHJldDsKPiArfQo+ICsKPiArc3RhdGljIGludCBkd2MzX3Fjb21fcmVtb3Zl KHN0cnVjdCBwbGF0Zm9ybV9kZXZpY2UgKnBkZXYpCj4gK3sKPiArCXN0cnVjdCBkd2MzX3Fjb20g KnFjb20gPSBwbGF0Zm9ybV9nZXRfZHJ2ZGF0YShwZGV2KTsKPiArCXN0cnVjdCBkZXZpY2UgKmRl diA9IHFjb20tPmRldjsKPiArCWludCBpOwo+ICsKPiArCW9mX3BsYXRmb3JtX2RlcG9wdWxhdGUo JnBkZXYtPmRldik7Cj4gKwo+ICsJZm9yIChpID0gcWNvbS0+bnVtX2Nsb2NrcyAtIDE7IGkgPj0g MDsgaS0tKSB7Cj4gKwkJY2xrX2Rpc2FibGVfdW5wcmVwYXJlKHFjb20tPmNsa3NbaV0pOwo+ICsJ CWNsa19wdXQocWNvbS0+Y2xrc1tpXSk7Cj4gKwl9Cj4gKwlxY29tLT5udW1fY2xvY2tzID0gMDsK PiArCj4gKwlyZXNldF9jb250cm9sX2Fzc2VydChxY29tLT5yZXNldHMpOwo+ICsJcmVzZXRfY29u dHJvbF9wdXQocWNvbS0+cmVzZXRzKTsKPiArCj4gKwlwbV9ydW50aW1lX2Rpc2FibGUoZGV2KTsK PiArCj4gKwlyZXR1cm4gMDsKPiArfQo+ICsKPiArI2lmZGVmIENPTkZJR19QTV9TTEVFUAo+ICtz dGF0aWMgaW50IGR3YzNfcWNvbV9wbV9zdXNwZW5kKHN0cnVjdCBkZXZpY2UgKmRldikKPiArewo+ ICsJc3RydWN0IGR3YzNfcWNvbSAqcWNvbSA9IGRldl9nZXRfZHJ2ZGF0YShkZXYpOwo+ICsJaW50 IHJldCA9IDA7Cj4gKwo+ICsJZGV2X2VycihkZXYsICJkd2MzLXFjb20gUE0gc3VzcGVuZFxuIik7 Cgp3aHkgYW4gZXJyb3IgbWVzc2FnZSBoZXJlPyBUaGVyZSdzIG5vIGVycm9yLiBSZW1vdmUgdGhp cywgaXQncyB1bm5lY2Vzc2FyeS4KCj4gKwlyZXQgPSBkd2MzX3Fjb21fc3VzcGVuZChxY29tKTsK PiArCWlmICghcmV0KQo+ICsJCXFjb20tPnBtX3N1c3BlbmRlZCA9IHRydWU7Cj4gKwo+ICsJcmV0 dXJuIHJldDsKPiArfQo+ICsKPiArc3RhdGljIGludCBkd2MzX3Fjb21fcG1fcmVzdW1lKHN0cnVj dCBkZXZpY2UgKmRldikKPiArewo+ICsJc3RydWN0IGR3YzNfcWNvbSAqcWNvbSA9IGRldl9nZXRf ZHJ2ZGF0YShkZXYpOwo+ICsJaW50IHJldDsKPiArCj4gKwlkZXZfZXJyKGRldiwgImR3YzMtcWNv bSBQTSByZXN1bWVcbiIpOwoKZGl0dG8KCj4gKwlyZXQgPSBkd2MzX3Fjb21fcmVzdW1lKHFjb20p Owo+ICsJaWYgKCFyZXQpCj4gKwkJcWNvbS0+cG1fc3VzcGVuZGVkID0gZmFsc2U7Cj4gKwo+ICsJ cmV0dXJuIHJldDsKPiArfQo+ICsjZW5kaWYKPiArCj4gKyNpZmRlZiBDT05GSUdfUE0KPiArc3Rh dGljIGludCBkd2MzX3Fjb21fcnVudGltZV9zdXNwZW5kKHN0cnVjdCBkZXZpY2UgKmRldikKPiAr ewo+ICsJc3RydWN0IGR3YzNfcWNvbSAqcWNvbSA9IGRldl9nZXRfZHJ2ZGF0YShkZXYpOwo+ICsK PiArCWRldl9lcnIoZGV2LCAiRFdDMy1xY29tIHJ1bnRpbWUgc3VzcGVuZFxuIik7CgpkaXR0bwoK PiArCXJldHVybiBkd2MzX3Fjb21fc3VzcGVuZChxY29tKTsKPiArfQo+ICsKPiArc3RhdGljIGlu dCBkd2MzX3Fjb21fcnVudGltZV9yZXN1bWUoc3RydWN0IGRldmljZSAqZGV2KQo+ICt7Cj4gKwlz dHJ1Y3QgZHdjM19xY29tICpxY29tID0gZGV2X2dldF9kcnZkYXRhKGRldik7Cj4gKwo+ICsJZGV2 X2VycihkZXYsICJEV0MzLXFjb20gcnVudGltZSByZXN1bWVcbiIpOwoKZGl0dG8KCj4gKwlyZXR1 cm4gZHdjM19xY29tX3Jlc3VtZShxY29tKTsKPiArfQo+ICsjZW5kaWYKPiArCj4gK3N0YXRpYyBj b25zdCBzdHJ1Y3QgZGV2X3BtX29wcyBkd2MzX3Fjb21fZGV2X3BtX29wcyA9IHsKPiArCVNFVF9T WVNURU1fU0xFRVBfUE1fT1BTKGR3YzNfcWNvbV9wbV9zdXNwZW5kLCBkd2MzX3Fjb21fcG1fcmVz dW1lKQo+ICsJU0VUX1JVTlRJTUVfUE1fT1BTKGR3YzNfcWNvbV9ydW50aW1lX3N1c3BlbmQsIGR3 YzNfcWNvbV9ydW50aW1lX3Jlc3VtZSwKPiArCQkJICAgTlVMTCkKCndoeSBkb24ndCB5b3UgaGF2 ZSBydW50aW1lX2lkbGU/Cg== From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Cyrus-Session-Id: sloti22d1t05-2930626-1520939318-2-11319288318556515828 X-Sieve: CMU Sieve 3.0 X-Spam-known-sender: no X-Spam-score: 0.0 X-Spam-hits: BAYES_00 -1.9, ME_NOAUTH 0.01, RCVD_IN_DNSWL_HI -5, T_RP_MATCHES_RCVD -0.01, T_TVD_MIME_EPI 0.01, LANGUAGES enro, BAYES_USED global, SA_VERSION 3.4.0 X-Spam-source: IP='209.132.180.67', Host='vger.kernel.org', Country='CN', FromHeader='org', MailFrom='org' X-Spam-charsets: X-Attached: signature.asc X-Resolved-to: greg@kroah.com X-Delivered-to: greg@kroah.com X-Mail-from: linux-usb-owner@vger.kernel.org ARC-Seal: i=1; a=rsa-sha256; cv=none; d=messagingengine.com; s=arctest; t=1520939317; b=RA+xwZ6NRqIAM0BqhBIzp1Wj7aWUiema7R6k1AiDWRqfafG iXthfWoTD+KDpluuiS9ckFHBBwjyrNWfm//17YPpG1Lrfd4+sZ9Lw4sqs4j6bM0J o8PuNqzaGzb5LJmUCLGYAPLns2OQaWkNCYYaCC5Za5Ejc1i9Z2RU31aHxcUOmE+2 rKvsDbL+Q6xc9vTIomR/+Pyhd690TkDK472Wwq5Y+u01uM9nRUwqQYyBPuSI7VS2 xYbvRyaO2xzyuCnSgOQYwslH+1O+qYMrto0eqdqdxWTj32Eakq/80Q4Z2U4fF/0N EuUB5s7AFzh64cCMhU8YK9ixdBRX2QEm74CFfeg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=from:to:cc:subject:in-reply-to:references :date:message-id:mime-version:content-type:sender:list-id; s= arctest; t=1520939317; bh=bdkgHw1AsDtP3uRlOU1mx3nuJn8/TbNpxPYOvJ gX5c0=; b=jV6LCuFmlNnvQLvzH9bBAw6qgRO+ZiZGmu5z851pjTkytR7nMlBRgS +qUeMJxvrHkASA38xbYmHLJz9LxiUEeWAd8cDmVkVExi+kNYakw8qkpCxHcBN/df /YzSjKiAfyUQ9/XEXFdFkoP9qFFz5ykfr3HGwrE7YlQWYuSrNHNUQAi1AHEgKrci zZq2ntay59RVfDuFJM3cpiUmrt7IpmPLI7mlunMVZl0JiQo+7/osPDKqCW6Yz10t YmcC14dxMWhtiTGQt2YPoRpj10qXkrGQSZwY3pM1ab4MN8si2TwPImYW1rdqHVpm ozZhfEXqteUPTr7c6lKmyapoNwOvOH/A== ARC-Authentication-Results: i=1; mx4.messagingengine.com; arc=none (no signatures found); dkim=none (no signatures found); dmarc=none (p=none,has-list-id=yes,d=none) header.from=kernel.org; iprev=pass policy.iprev=209.132.180.67 (vger.kernel.org); smime=temperror; spf=none smtp.mailfrom=linux-usb-owner@vger.kernel.org smtp.helo=vger.kernel.org; x-aligned-from=orgdomain_pass; x-category=clean score=-100 state=0; x-ptr=pass x-ptr-helo=vger.kernel.org x-ptr-lookup=vger.kernel.org; x-return-mx=pass smtp.domain=vger.kernel.org smtp.result=pass smtp_org.domain=kernel.org smtp_org.result=pass smtp_is_org_domain=no header.domain=kernel.org header.result=pass header_is_org_domain=yes Authentication-Results: mx4.messagingengine.com; arc=none (no signatures found); dkim=none (no signatures found); dmarc=none (p=none,has-list-id=yes,d=none) header.from=kernel.org; iprev=pass policy.iprev=209.132.180.67 (vger.kernel.org); smime=temperror; spf=none smtp.mailfrom=linux-usb-owner@vger.kernel.org smtp.helo=vger.kernel.org; x-aligned-from=orgdomain_pass; x-category=clean score=-100 state=0; x-ptr=pass x-ptr-helo=vger.kernel.org x-ptr-lookup=vger.kernel.org; x-return-mx=pass smtp.domain=vger.kernel.org smtp.result=pass smtp_org.domain=kernel.org smtp_org.result=pass smtp_is_org_domain=no header.domain=kernel.org header.result=pass header_is_org_domain=yes Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932724AbeCMLIf (ORCPT ); Tue, 13 Mar 2018 07:08:35 -0400 Received: from mga07.intel.com ([134.134.136.100]:64240 "EHLO mga07.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752396AbeCMLId (ORCPT ); Tue, 13 Mar 2018 07:08:33 -0400 X-Amp-Result: UNSCANNABLE X-Amp-File-Uploaded: False X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.47,464,1515484800"; d="asc'?scan'208";a="182240708" From: Felipe Balbi To: Manu Gautam , Rob Herring , Andy Gross Cc: linux-arm-msm@vger.kernel.org, linux-usb@vger.kernel.org, Manu Gautam , Greg Kroah-Hartman , open list Subject: Re: [PATCH v1 2/2] usb: dwc3: Add Qualcomm DWC3 glue driver In-Reply-To: <1520937362-28777-2-git-send-email-mgautam@codeaurora.org> References: <1520937362-28777-1-git-send-email-mgautam@codeaurora.org> <1520937362-28777-2-git-send-email-mgautam@codeaurora.org> Date: Tue, 13 Mar 2018 13:08:14 +0200 Message-ID: <878taw8c81.fsf@linux.intel.com> MIME-Version: 1.0 Content-Type: multipart/signed; boundary="=-=-="; micalg=pgp-sha512; protocol="application/pgp-signature" Sender: linux-usb-owner@vger.kernel.org X-Mailing-List: linux-usb@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-Mailing-List: linux-kernel@vger.kernel.org List-ID: --=-=-= Content-Type: text/plain Content-Transfer-Encoding: quoted-printable Hi, +Andy Manu Gautam writes: > DWC3 controller on Qualcomm SOCs has a Qscratch wrapper. > Some of its uses are described below resulting in need to > have a separate glue driver instead of using dwc3-of-simple: > - It exposes register interface to override vbus-override > and lane0-pwr-present signals going to hardware. These > must be updated in peripheral mode for DWC3 if vbus lines > are not connected to hardware block. Otherwise RX termination > in SS mode or DP pull-up is not applied by device controller. right, core needs to know that VBUS is above 4.4V. Why wasn't this a problem when the original glue layer was first published? > - pwr_events_irq_stat support to ensure USB2 PHY is in L2 state > before glue driver can turn-off clocks and suspend PHY. Core manages PHY suspend automatically. Isn't that working for you? Why? > - Support for wakeup interrupts lines that are asserted whenever > there is any wakeup event on USB3 or USB2 bus. ok > - Support to replace pip3 clock going to DWC3 with utmi clock > for hardware configuration where SSPHY is not used with DWC3. Is that SW configurable? Really? In any case seems like this and SESSVLD valid should be handled using Hans' and Heikki's mux support. > Other than above hardware features in Qscratch wrapper there > are some limitations on QCOM SOCs that require special handling > of power management e.g. suspending PHY using GUSB2PHYCFG > register and ensuring PHY enters L2 before turning off clocks etc. > > Signed-off-by: Manu Gautam > --- > drivers/usb/dwc3/Kconfig | 11 + > drivers/usb/dwc3/Makefile | 1 + > drivers/usb/dwc3/dwc3-of-simple.c | 1 - > drivers/usb/dwc3/dwc3-qcom.c | 635 ++++++++++++++++++++++++++++++++= ++++++ > 4 files changed, 647 insertions(+), 1 deletion(-) > create mode 100644 drivers/usb/dwc3/dwc3-qcom.c > > diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig > index ab8c0e0..f5bb4f1 100644 > --- a/drivers/usb/dwc3/Kconfig > +++ b/drivers/usb/dwc3/Kconfig > @@ -106,4 +106,15 @@ config USB_DWC3_ST > inside (i.e. STiH407). > Say 'Y' or 'M' if you have one such device. >=20=20 > +config USB_DWC3_QCOM > + tristate "Qualcomm Platform" > + depends on ARCH_QCOM || COMPILE_TEST > + depends on OF > + default USB_DWC3 > + help > + Some Qualcomm SoCs use DesignWare Core IP for USB2/3 > + functionality. > + > + Say 'Y' or 'M' if you have one such device. > + > endif > diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile > index 7ac7250..c3ce697 100644 > --- a/drivers/usb/dwc3/Makefile > +++ b/drivers/usb/dwc3/Makefile > @@ -48,3 +48,4 @@ obj-$(CONFIG_USB_DWC3_PCI) +=3D dwc3-pci.o > obj-$(CONFIG_USB_DWC3_KEYSTONE) +=3D dwc3-keystone.o > obj-$(CONFIG_USB_DWC3_OF_SIMPLE) +=3D dwc3-of-simple.o > obj-$(CONFIG_USB_DWC3_ST) +=3D dwc3-st.o > +obj-$(CONFIG_USB_DWC3_QCOM) +=3D dwc3-qcom.o > diff --git a/drivers/usb/dwc3/dwc3-of-simple.c b/drivers/usb/dwc3/dwc3-of= -simple.c > index cb2ee96..0fd0e8e 100644 > --- a/drivers/usb/dwc3/dwc3-of-simple.c > +++ b/drivers/usb/dwc3/dwc3-of-simple.c > @@ -208,7 +208,6 @@ static int dwc3_of_simple_runtime_resume(struct devic= e *dev) > }; >=20=20 > static const struct of_device_id of_dwc3_simple_match[] =3D { > - { .compatible =3D "qcom,dwc3" }, > { .compatible =3D "rockchip,rk3399-dwc3" }, > { .compatible =3D "xlnx,zynqmp-dwc3" }, > { .compatible =3D "cavium,octeon-7130-usb-uctl" }, > diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c > new file mode 100644 > index 0000000..917199e > --- /dev/null > +++ b/drivers/usb/dwc3/dwc3-qcom.c > @@ -0,0 +1,635 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. > + * > + * Inspired by dwc3-of-simple.c > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "core.h" > +#include "io.h" you must be kidding, right? There's no way I'm gonna let a glue poke at core registers. > +static void dwc3_qcom_suspend_hsphy(struct dwc3_qcom *qcom) > +{ > + struct dwc3 *dwc =3D platform_get_drvdata(qcom->dwc3); > + int ret; > + u32 val; > + > + /* Clear previous L2 events */ > + dwc3_qcom_setbits(qcom->qscratch_base, PWR_EVNT_IRQ_STAT_REG, > + PWR_EVNT_LPM_IN_L2_MASK | PWR_EVNT_LPM_OUT_L2_MASK); > + > + /* Allow controller to suspend HSPHY */ > + val =3D dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); > + val |=3D DWC3_GUSB2PHYCFG_ENBLSLPM | DWC3_GUSB2PHYCFG_SUSPHY; > + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), val); core should handle PHY bits. In any case, why don't you let core handle PHY suspend? It handles it automatically for us, there should be no need for SW intervention. > +static int dwc3_qcom_suspend(struct dwc3_qcom *qcom) > +{ > + struct dwc3 *dwc =3D platform_get_drvdata(qcom->dwc3); nope! Glue shouldn't touch dwc3 at all. > + int i; > + > + if (qcom->is_suspended) > + return 0; > + > + if (!dwc) > + return -EBUSY; =2DENODEV? > + dwc3_qcom_suspend_hsphy(qcom); > + > + if (dwc->usb2_generic_phy) > + phy_pm_runtime_put_sync(dwc->usb2_generic_phy); > + if (dwc->usb3_generic_phy) > + phy_pm_runtime_put_sync(dwc->usb3_generic_phy); core.c should do this. > + /* Disable HSPHY auto suspend */ > + val =3D dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); > + val &=3D ~(DWC3_GUSB2PHYCFG_ENBLSLPM | DWC3_GUSB2PHYCFG_SUSPHY); > + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), val); > + > + qcom->is_suspended =3D false; > + > + dev_dbg(qcom->dev, "DWC3 exited from low power mode\n"); no dev_dbg() or dev_info() in this driver. > +static irqreturn_t qcom_dwc3_resume_irq(int irq, void *data) > +{ > + struct dwc3_qcom *qcom =3D data; > + struct dwc3 *dwc =3D platform_get_drvdata(qcom->dwc3); > + > + /* If pm_suspended then let pm_resume take care of resuming h/w */ > + if (qcom->pm_suspended) > + return IRQ_HANDLED; > + > + dwc3_qcom_resume(qcom); instead, why don't you pm_runtime_resume() here, and let runtime_resume() handle dwc3_qcom_resume() ? > +static int dwc3_qcom_clk_init(struct dwc3_qcom *qcom, int count) > +{ > + struct device *dev =3D qcom->dev; > + struct device_node *np =3D dev->of_node; > + int i; > + > + qcom->num_clocks =3D count; > + > + if (!count) > + return 0; > + > + qcom->clks =3D devm_kcalloc(dev, qcom->num_clocks, > + sizeof(struct clk *), GFP_KERNEL); > + if (!qcom->clks) > + return -ENOMEM; > + > + for (i =3D 0; i < qcom->num_clocks; i++) { > + struct clk *clk; > + int ret; > + > + clk =3D of_clk_get(np, i); > + if (IS_ERR(clk)) { > + while (--i >=3D 0) > + clk_put(qcom->clks[i]); > + return PTR_ERR(clk); > + } > + > + ret =3D clk_prepare_enable(clk); > + if (ret < 0) { > + while (--i >=3D 0) { > + clk_disable_unprepare(qcom->clks[i]); > + clk_put(qcom->clks[i]); > + } > + clk_put(clk); > + > + return ret; > + } > + > + qcom->clks[i] =3D clk; > + } > + > + return 0; > +} > + > +static int dwc3_qcom_probe(struct platform_device *pdev) > +{ > + struct device_node *np =3D pdev->dev.of_node, *dwc3_np; > + struct dwc3_qcom *qcom; > + struct resource *res; > + int irq, ret, i; > + bool ignore_pipe_clk; > + > + qcom =3D devm_kzalloc(&pdev->dev, sizeof(*qcom), GFP_KERNEL); > + if (!qcom) > + return -ENOMEM; > + > + platform_set_drvdata(pdev, qcom); > + qcom->dev =3D &pdev->dev; > + > + qcom->resets =3D of_reset_control_array_get_optional_exclusive(np); > + if (IS_ERR(qcom->resets)) { > + ret =3D PTR_ERR(qcom->resets); > + dev_err(&pdev->dev, "failed to get resets, err=3D%d\n", ret); > + return ret; > + } > + > + ret =3D reset_control_deassert(qcom->resets); > + if (ret) > + goto reset_put; > + > + ret =3D dwc3_qcom_clk_init(qcom, of_clk_get_parent_count(np)); > + if (ret) { > + dev_err(qcom->dev, "failed to get clocks\n"); > + goto reset_assert; > + } > + > + res =3D platform_get_resource_byname(pdev, IORESOURCE_MEM, "qscratch"); > + qcom->qscratch_base =3D devm_ioremap_resource(qcom->dev, res); > + if (IS_ERR(qcom->qscratch_base)) { > + dev_err(qcom->dev, "failed to map qscratch - %d\n", ret); > + ret =3D PTR_ERR(qcom->qscratch_base); > + goto clk_disable; > + } > + > + irq =3D platform_get_irq_byname(pdev, "hs_phy_irq"); > + if (irq > 0) { > + ret =3D devm_request_threaded_irq(qcom->dev, irq, NULL, > + qcom_dwc3_resume_irq, > + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, > + "qcom_dwc3 HS", qcom); > + if (ret) { > + dev_err(qcom->dev, "hs_phy_irq failed: %d\n", ret); > + goto clk_disable; > + } > + } > + > + irq =3D platform_get_irq_byname(pdev, "dp_hs_phy_irq"); > + if (irq > 0) { > + irq_set_status_flags(irq, IRQ_NOAUTOEN); why do you need to set this flag? > + ret =3D devm_request_threaded_irq(qcom->dev, irq, NULL, > + qcom_dwc3_resume_irq, > + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, > + "qcom_dwc3 DP_HS", qcom); this is the same as devm_request_irq() > + if (ret) { > + dev_err(qcom->dev, "dp_hs_phy_irq failed: %d\n", ret); > + goto clk_disable; > + } > + qcom->dp_hs_phy_irq =3D irq; > + } > + > + irq =3D platform_get_irq_byname(pdev, "dm_hs_phy_irq"); > + if (irq > 0) { > + irq_set_status_flags(irq, IRQ_NOAUTOEN); > + ret =3D devm_request_threaded_irq(qcom->dev, irq, NULL, > + qcom_dwc3_resume_irq, > + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, > + "qcom_dwc3 DM_HS", qcom); > + if (ret) { > + dev_err(qcom->dev, "dm_hs_phy_irq failed: %d\n", ret); > + goto clk_disable; > + } > + qcom->dm_hs_phy_irq =3D irq; > + } > + > + irq =3D platform_get_irq_byname(pdev, "ss_phy_irq"); > + if (irq > 0) { > + irq_set_status_flags(irq, IRQ_NOAUTOEN); > + ret =3D devm_request_threaded_irq(qcom->dev, irq, NULL, > + qcom_dwc3_resume_irq, > + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, > + "qcom_dwc3 SS", qcom); > + if (ret) { > + dev_err(qcom->dev, "ss_phy_irq failed: %d\n", ret); > + goto clk_disable; > + } > + qcom->ss_phy_irq =3D irq; > + } > + > + dwc3_np =3D of_get_child_by_name(np, "dwc3"); > + if (!dwc3_np) { > + dev_err(qcom->dev, "failed to find dwc3 core child\n"); > + ret =3D -ENODEV; > + goto clk_disable; > + } > + > + /* > + * Disable pipe_clk requirement if specified. Used when dwc3 > + * operates without SSPHY and only HS/FS/LS modes are supported. > + */ > + ignore_pipe_clk =3D device_property_read_bool(qcom->dev, > + "qcom,select-utmi-as-pipe-clk"); > + if (ignore_pipe_clk) > + dwc3_qcom_select_utmi_clk(qcom); > + > + ret =3D of_platform_populate(np, NULL, NULL, qcom->dev); > + if (ret) { > + dev_err(qcom->dev, "failed to register dwc3 core - %d\n", ret); > + goto clk_disable; > + } > + > + qcom->dwc3 =3D of_find_device_by_node(dwc3_np); > + if (!qcom->dwc3) { > + dev_err(&pdev->dev, "failed to get dwc3 platform device\n"); > + goto depopulate; > + } > + > + qcom->mode =3D usb_get_dr_mode(&qcom->dwc3->dev); > + > + /* register extcon to override vbus later on mode switch */ > + if (qcom->mode =3D=3D USB_DR_MODE_OTG) { > + ret =3D dwc3_qcom_register_extcon(qcom); > + if (ret) > + goto depopulate; > + } else if (qcom->mode =3D=3D USB_DR_MODE_PERIPHERAL) { > + /* enable vbus override for device mode */ > + dwc3_qcom_vbus_overrride_enable(qcom, true); > + } > + > + device_init_wakeup(&pdev->dev, 1); > + qcom->is_suspended =3D false; > + pm_runtime_set_active(qcom->dev); > + pm_runtime_enable(qcom->dev); > + > + return 0; > + > +depopulate: > + of_platform_depopulate(&pdev->dev); > +clk_disable: > + for (i =3D qcom->num_clocks - 1; i >=3D 0; i--) { > + clk_disable_unprepare(qcom->clks[i]); > + clk_put(qcom->clks[i]); > + } > +reset_assert: > + reset_control_assert(qcom->resets); > +reset_put: > + reset_control_put(qcom->resets); > + > + return ret; > +} > + > +static int dwc3_qcom_remove(struct platform_device *pdev) > +{ > + struct dwc3_qcom *qcom =3D platform_get_drvdata(pdev); > + struct device *dev =3D qcom->dev; > + int i; > + > + of_platform_depopulate(&pdev->dev); > + > + for (i =3D qcom->num_clocks - 1; i >=3D 0; i--) { > + clk_disable_unprepare(qcom->clks[i]); > + clk_put(qcom->clks[i]); > + } > + qcom->num_clocks =3D 0; > + > + reset_control_assert(qcom->resets); > + reset_control_put(qcom->resets); > + > + pm_runtime_disable(dev); > + > + return 0; > +} > + > +#ifdef CONFIG_PM_SLEEP > +static int dwc3_qcom_pm_suspend(struct device *dev) > +{ > + struct dwc3_qcom *qcom =3D dev_get_drvdata(dev); > + int ret =3D 0; > + > + dev_err(dev, "dwc3-qcom PM suspend\n"); why an error message here? There's no error. Remove this, it's unnecessary. > + ret =3D dwc3_qcom_suspend(qcom); > + if (!ret) > + qcom->pm_suspended =3D true; > + > + return ret; > +} > + > +static int dwc3_qcom_pm_resume(struct device *dev) > +{ > + struct dwc3_qcom *qcom =3D dev_get_drvdata(dev); > + int ret; > + > + dev_err(dev, "dwc3-qcom PM resume\n"); ditto > + ret =3D dwc3_qcom_resume(qcom); > + if (!ret) > + qcom->pm_suspended =3D false; > + > + return ret; > +} > +#endif > + > +#ifdef CONFIG_PM > +static int dwc3_qcom_runtime_suspend(struct device *dev) > +{ > + struct dwc3_qcom *qcom =3D dev_get_drvdata(dev); > + > + dev_err(dev, "DWC3-qcom runtime suspend\n"); ditto > + return dwc3_qcom_suspend(qcom); > +} > + > +static int dwc3_qcom_runtime_resume(struct device *dev) > +{ > + struct dwc3_qcom *qcom =3D dev_get_drvdata(dev); > + > + dev_err(dev, "DWC3-qcom runtime resume\n"); ditto > + return dwc3_qcom_resume(qcom); > +} > +#endif > + > +static const struct dev_pm_ops dwc3_qcom_dev_pm_ops =3D { > + SET_SYSTEM_SLEEP_PM_OPS(dwc3_qcom_pm_suspend, dwc3_qcom_pm_resume) > + SET_RUNTIME_PM_OPS(dwc3_qcom_runtime_suspend, dwc3_qcom_runtime_resume, > + NULL) why don't you have runtime_idle? =2D-=20 balbi --=-=-= Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- iQIzBAEBCgAdFiEElLzh7wn96CXwjh2IzL64meEamQYFAlqnsR4ACgkQzL64meEa mQaM2hAAtpcjjx2FtDuNsiIx7EMT84EnJjt6o60odgNAvg3GwaxFMR405mpskyUf EbBSAuMI3CGQyBjB/zHigZdco5KTpVnFMu5ksFaAcZVP1JGmqWsGN6JVOkk9KEv9 42HZhawXDOzzc7BlJ1scoegomjx/sByIGfHtLFHGeG3idexSEKbd8oUG87mwwBM2 ldT5RNwKb+VLyIdCssdnbbJoZ0ZXC7ESXMfQ4DbSGzWaD0KTKXHCOh/cJdceuAJq TjC7c1YDQFbTJDSoepk4LkH3h90xEpPVtTokh5pz9MMRmyZDer7AkVW51uzKNi9b J6uRCPmvPjX+CkHtbS7L/vVOEowQy7TxwPA+ZMKyYvdxzrJx/KSCbe3Irx8tSB0E Lkkre3a9/rhtrBvQ5MW5jvkh00Hv1JPxjVh99ZZBUQ0Zb7mPWZYA3j7eSDGofMOz NZml3hi05jGqtrXqQduHU0UwcXQbfbBQY+VThYOyaKlG8cBV8t4fISJXaaAP/2lO C/cBnXAKokmKkOL9+p0YRVUp67KLJZNtoEbvvUjX/sA/MSTW9Y0OPBFganTJTXZ/ UlK5W7AJ7UIvlx0rPipiPmam0AyE1uSgaVWPzfWJeaY5Hu9aHKWiC4PnnZ576viP lo6Z65BK6wEBlvfmA1zdC9rcPQtsqsuLuxnu7t6KIU0l/Kc8UZY= =LJgf -----END PGP SIGNATURE----- --=-=-=--