From mboxrd@z Thu Jan 1 00:00:00 1970 From: Jorge Ramirez-Ortiz Subject: [PATCH v2 2/2] phy: qualcomm: usb: Add Super-Speed PHY driver Date: Tue, 29 Jan 2019 12:35:15 +0100 Message-ID: <1548761715-4004-3-git-send-email-jorge.ramirez-ortiz@linaro.org> References: <1548761715-4004-1-git-send-email-jorge.ramirez-ortiz@linaro.org> Return-path: In-Reply-To: <1548761715-4004-1-git-send-email-jorge.ramirez-ortiz@linaro.org> Sender: linux-kernel-owner@vger.kernel.org To: jorge.ramirez-ortiz@linaro.org, gregkh@linuxfoundation.org, mark.rutland@arm.com, kishon@ti.com, jackp@codeaurora.org, andy.gross@linaro.org, swboyd@chromium.org Cc: shawn.guo@linaro.org, vkoul@kernel.org, bjorn.andersson@linaro.org, khasim.mohammed@linaro.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-arm-msm@vger.kernel.org, linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org List-Id: linux-arm-msm@vger.kernel.org Driver to control the Synopsys SS PHY 1.0.0 implemeneted in QCS404 Based on Sriharsha Allenki's original code. Signed-off-by: Jorge Ramirez-Ortiz --- drivers/phy/qualcomm/Kconfig | 11 ++ drivers/phy/qualcomm/Makefile | 1 + drivers/phy/qualcomm/phy-qcom-usb-ss.c | 347 +++++++++++++++++++++++++++++++++ 3 files changed, 359 insertions(+) create mode 100644 drivers/phy/qualcomm/phy-qcom-usb-ss.c diff --git a/drivers/phy/qualcomm/Kconfig b/drivers/phy/qualcomm/Kconfig index c7b5ee8..35a5a67 100644 --- a/drivers/phy/qualcomm/Kconfig +++ b/drivers/phy/qualcomm/Kconfig @@ -92,3 +92,14 @@ config PHY_QCOM_USB_HS_SNPS_28NM Enable this to support the Synopsys 28nm Femto USB PHY on Qualcomm chips. This driver supports the high-speed PHY which is usually paired with either the ChipIdea or Synopsys DWC3 USB IPs on MSM SOCs. + +config PHY_QCOM_USB_SS + tristate "Qualcomm USB SS PHY driver" + depends on ARCH_QCOM || COMPILE_TEST + depends on EXTCON || !EXTCON # if EXTCON=m, this cannot be built-in + select GENERIC_PHY + help + Enable this to support the Super-Speed USB transceiver on Qualcomm + chips. This driver supports the PHY which uses the QSCRATCH-based + register set for its control sequences, normally paired with newer + DWC3-based Super-Speed controllers on Qualcomm SoCs. diff --git a/drivers/phy/qualcomm/Makefile b/drivers/phy/qualcomm/Makefile index dc238d9..7149261 100644 --- a/drivers/phy/qualcomm/Makefile +++ b/drivers/phy/qualcomm/Makefile @@ -10,3 +10,4 @@ obj-$(CONFIG_PHY_QCOM_UFS_20NM) += phy-qcom-ufs-qmp-20nm.o obj-$(CONFIG_PHY_QCOM_USB_HS) += phy-qcom-usb-hs.o obj-$(CONFIG_PHY_QCOM_USB_HSIC) += phy-qcom-usb-hsic.o obj-$(CONFIG_PHY_QCOM_USB_HS_SNPS_28NM) += phy-qcom-usb-hs-snsp-28nm.o +obj-$(CONFIG_PHY_QCOM_USB_SS) += phy-qcom-usb-ss.o diff --git a/drivers/phy/qualcomm/phy-qcom-usb-ss.c b/drivers/phy/qualcomm/phy-qcom-usb-ss.c new file mode 100644 index 0000000..e6ae96e --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-usb-ss.c @@ -0,0 +1,347 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2012-2014,2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2018, Linaro Limited + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PHY_CTRL0 0x6C +#define PHY_CTRL1 0x70 +#define PHY_CTRL2 0x74 +#define PHY_CTRL4 0x7C + +/* PHY_CTRL bits */ +#define REF_PHY_EN BIT(0) +#define LANE0_PWR_ON BIT(2) +#define SWI_PCS_CLK_SEL BIT(4) +#define TST_PWR_DOWN BIT(4) +#define PHY_RESET BIT(7) + +enum phy_vdd_ctrl { ENABLE, DISABLE, }; +enum phy_regulator { VDD, VDDA1P8, }; + +struct ssphy_priv { + void __iomem *base; + struct device *dev; + struct reset_control *reset_com; + struct reset_control *reset_phy; + struct regulator *vbus; + struct regulator_bulk_data *regs; + int num_regs; + struct clk_bulk_data *clks; + int num_clks; + enum phy_mode mode; +}; + +static inline void qcom_ssphy_updatel(void __iomem *addr, u32 mask, u32 val) +{ + writel((readl(addr) & ~mask) | val, addr); +} + +static inline int qcom_ssphy_vbus_enable(struct regulator *vbus) +{ + return !regulator_is_enabled(vbus) ? regulator_enable(vbus) : 0; +} + +static inline int qcom_ssphy_vbus_disable(struct regulator *vbus) +{ + return regulator_is_enabled(vbus) ? regulator_disable(vbus) : 0; +} + +static int qcom_ssphy_vdd_ctrl(struct ssphy_priv *priv, enum phy_vdd_ctrl ctrl) +{ + const int vdd_min = ctrl == ENABLE ? 1050000 : 0; + const int vdd_max = 1050000; + int ret; + + ret = regulator_set_voltage(priv->regs[VDD].consumer, vdd_min, vdd_max); + if (ret) + dev_err(priv->dev, "Failed to set regulator vdd to %d\n", + vdd_min); + + return ret; +} + +static int qcom_ssphy_vbus_ctrl(struct regulator *vbus, enum phy_mode mode) +{ + if (!vbus) + return 0; + + if (mode == PHY_MODE_INVALID) + return 0; + + /* gadget attached */ + if (mode == PHY_MODE_USB_HOST) + return qcom_ssphy_vbus_enable(vbus); + + /* USB_DEVICE: gadget removed: enable detection */ + return qcom_ssphy_vbus_disable(vbus); +} + +static int qcom_ssphy_do_reset(struct ssphy_priv *priv) +{ + int ret; + + if (!priv->reset_com) { + qcom_ssphy_updatel(priv->base + PHY_CTRL1, PHY_RESET, + PHY_RESET); + usleep_range(10, 20); + qcom_ssphy_updatel(priv->base + PHY_CTRL1, PHY_RESET, 0); + } else { + ret = reset_control_assert(priv->reset_com); + if (ret) { + dev_err(priv->dev, "Failed to assert reset com\n"); + return ret; + } + + ret = reset_control_assert(priv->reset_phy); + if (ret) { + dev_err(priv->dev, "Failed to assert reset phy\n"); + return ret; + } + + usleep_range(10, 20); + + ret = reset_control_deassert(priv->reset_com); + if (ret) { + dev_err(priv->dev, "Failed to deassert reset com\n"); + return ret; + } + + ret = reset_control_deassert(priv->reset_phy); + if (ret) { + dev_err(priv->dev, "Failed to deassert reset phy\n"); + return ret; + } + } + + return 0; +} + +static int qcom_ssphy_power_on(struct phy *phy) +{ + struct ssphy_priv *priv = phy_get_drvdata(phy); + int ret; + + ret = qcom_ssphy_vdd_ctrl(priv, ENABLE); + if (ret) + return ret; + + ret = regulator_bulk_enable(priv->num_regs, priv->regs); + if (ret) + goto err1; + + ret = clk_bulk_prepare_enable(priv->num_clks, priv->clks); + if (ret) + goto err2; + + ret = qcom_ssphy_vbus_ctrl(priv->vbus, priv->mode); + if (ret) + goto err3; + + ret = qcom_ssphy_do_reset(priv); + if (ret) + goto err4; + + writeb(SWI_PCS_CLK_SEL, priv->base + PHY_CTRL0); + qcom_ssphy_updatel(priv->base + PHY_CTRL4, LANE0_PWR_ON, LANE0_PWR_ON); + qcom_ssphy_updatel(priv->base + PHY_CTRL2, REF_PHY_EN, REF_PHY_EN); + qcom_ssphy_updatel(priv->base + PHY_CTRL4, TST_PWR_DOWN, 0); + + return 0; +err4: + if (priv->vbus && priv->mode != PHY_MODE_INVALID) + qcom_ssphy_vbus_disable(priv->vbus); +err3: + clk_bulk_disable_unprepare(priv->num_clks, priv->clks); +err2: + regulator_bulk_disable(priv->num_regs, priv->regs); +err1: + qcom_ssphy_vdd_ctrl(priv, DISABLE); + + return ret; +} + +static int qcom_ssphy_power_off(struct phy *phy) +{ + struct ssphy_priv *priv = phy_get_drvdata(phy); + + qcom_ssphy_updatel(priv->base + PHY_CTRL4, LANE0_PWR_ON, 0); + qcom_ssphy_updatel(priv->base + PHY_CTRL2, REF_PHY_EN, 0); + qcom_ssphy_updatel(priv->base + PHY_CTRL4, TST_PWR_DOWN, TST_PWR_DOWN); + + clk_bulk_disable_unprepare(priv->num_clks, priv->clks); + regulator_bulk_disable(priv->num_regs, priv->regs); + + if (priv->vbus && priv->mode != PHY_MODE_INVALID) + qcom_ssphy_vbus_disable(priv->vbus); + + qcom_ssphy_vdd_ctrl(priv, DISABLE); + + return 0; +} + +static int qcom_ssphy_init_clock(struct ssphy_priv *priv) +{ + const char * const clk_id[] = { "ref", "phy", "pipe", }; + int i; + + priv->num_clks = ARRAY_SIZE(clk_id); + priv->clks = devm_kcalloc(priv->dev, priv->num_clks, + sizeof(*priv->clks), GFP_KERNEL); + if (!priv->clks) + return -ENOMEM; + + for (i = 0; i < priv->num_clks; i++) + priv->clks[i].id = clk_id[i]; + + return devm_clk_bulk_get(priv->dev, priv->num_clks, priv->clks); +} + +static int qcom_ssphy_init_regulator(struct ssphy_priv *priv) +{ + const char * const reg_supplies[] = { + [VDD] = "vdd", + [VDDA1P8] = "vdda1p8", + }; + int ret, i; + + priv->num_regs = ARRAY_SIZE(reg_supplies); + priv->regs = devm_kcalloc(priv->dev, priv->num_regs, + sizeof(*priv->regs), GFP_KERNEL); + if (!priv->regs) + return -ENOMEM; + + for (i = 0; i < priv->num_regs; i++) + priv->regs[i].supply = reg_supplies[i]; + + ret = devm_regulator_bulk_get(priv->dev, priv->num_regs, priv->regs); + if (ret) + return ret; + + priv->vbus = devm_regulator_get_optional(priv->dev, "vbus"); + if (IS_ERR(priv->vbus)) + return PTR_ERR(priv->vbus); + + return 0; +} + +static int qcom_ssphy_init_reset(struct ssphy_priv *priv) +{ + priv->reset_com = devm_reset_control_get_optional(priv->dev, "com"); + if (IS_ERR(priv->reset_com)) { + dev_err(priv->dev, "Failed to get reset control com\n"); + return PTR_ERR(priv->reset_com); + } + + if (priv->reset_com) { + /* if reset_com is present, reset_phy is no longer optional */ + priv->reset_phy = devm_reset_control_get(priv->dev, "phy"); + if (IS_ERR(priv->reset_phy)) { + dev_err(priv->dev, "Failed to get reset control phy\n"); + return PTR_ERR(priv->reset_phy); + } + } + + return 0; +} + +static int qcom_ssphy_set_mode(struct phy *phy, enum phy_mode mode, int submode) +{ + struct ssphy_priv *priv = phy_get_drvdata(phy); + + if (!priv->vbus) + return 0; + + if (mode != PHY_MODE_USB_HOST && mode != PHY_MODE_USB_DEVICE) + return -EINVAL; + + priv->mode = mode; + + dev_dbg(priv->dev, "mode %d", mode); + + return qcom_ssphy_vbus_ctrl(priv->vbus, priv->mode); +} + +static const struct phy_ops qcom_ssphy_ops = { + .set_mode = qcom_ssphy_set_mode, + .power_off = qcom_ssphy_power_off, + .power_on = qcom_ssphy_power_on, + .owner = THIS_MODULE, +}; + +static int qcom_ssphy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct phy_provider *provider; + struct ssphy_priv *priv; + struct resource *res; + struct phy *phy; + int ret; + + priv = devm_kzalloc(dev, sizeof(struct ssphy_priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = dev; + priv->mode = PHY_MODE_INVALID; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->base = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + ret = qcom_ssphy_init_clock(priv); + if (ret) + return ret; + + ret = qcom_ssphy_init_reset(priv); + if (ret) + return ret; + + ret = qcom_ssphy_init_regulator(priv); + if (ret) + return ret; + + phy = devm_phy_create(dev, dev->of_node, &qcom_ssphy_ops); + if (IS_ERR(phy)) { + dev_err(dev, "Failed to create the SS phy\n"); + return PTR_ERR(phy); + } + + phy_set_drvdata(phy, priv); + + provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(provider); +} + +static const struct of_device_id qcom_ssphy_match[] = { + { .compatible = "qcom,usb-ssphy", }, + { }, +}; +MODULE_DEVICE_TABLE(of, qcom_ssphy_match); + +static struct platform_driver qcom_ssphy_driver = { + .probe = qcom_ssphy_probe, + .driver = { + .name = "qcom_usb_ssphy", + .of_match_table = qcom_ssphy_match, + }, +}; +module_platform_driver(qcom_ssphy_driver); + +MODULE_DESCRIPTION("Qualcomm Super-Speed USB PHY driver"); +MODULE_LICENSE("GPL v2"); -- 2.7.4 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: [v2,2/2] phy: qualcomm: usb: Add Super-Speed PHY driver From: Jorge Ramirez Message-Id: <1548761715-4004-3-git-send-email-jorge.ramirez-ortiz@linaro.org> Date: Tue, 29 Jan 2019 12:35:15 +0100 To: jorge.ramirez-ortiz@linaro.org, gregkh@linuxfoundation.org, mark.rutland@arm.com, kishon@ti.com, jackp@codeaurora.org, andy.gross@linaro.org, swboyd@chromium.org Cc: shawn.guo@linaro.org, vkoul@kernel.org, bjorn.andersson@linaro.org, khasim.mohammed@linaro.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-arm-msm@vger.kernel.org, linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org List-ID: RHJpdmVyIHRvIGNvbnRyb2wgdGhlIFN5bm9wc3lzIFNTIFBIWSAxLjAuMCBpbXBsZW1lbmV0ZWQg aW4gUUNTNDA0CkJhc2VkIG9uIFNyaWhhcnNoYSBBbGxlbmtpJ3MgPHNhbGxlbmtpQGNvZGVhdXJv cmEub3JnPiBvcmlnaW5hbCBjb2RlLgoKU2lnbmVkLW9mZi1ieTogSm9yZ2UgUmFtaXJlei1PcnRp eiA8am9yZ2UucmFtaXJlei1vcnRpekBsaW5hcm8ub3JnPgotLS0KIGRyaXZlcnMvcGh5L3F1YWxj b21tL0tjb25maWcgICAgICAgICAgIHwgIDExICsrCiBkcml2ZXJzL3BoeS9xdWFsY29tbS9NYWtl ZmlsZSAgICAgICAgICB8ICAgMSArCiBkcml2ZXJzL3BoeS9xdWFsY29tbS9waHktcWNvbS11c2It c3MuYyB8IDM0NyArKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysKIDMgZmlsZXMgY2hh bmdlZCwgMzU5IGluc2VydGlvbnMoKykKIGNyZWF0ZSBtb2RlIDEwMDY0NCBkcml2ZXJzL3BoeS9x dWFsY29tbS9waHktcWNvbS11c2Itc3MuYwoKZGlmZiAtLWdpdCBhL2RyaXZlcnMvcGh5L3F1YWxj b21tL0tjb25maWcgYi9kcml2ZXJzL3BoeS9xdWFsY29tbS9LY29uZmlnCmluZGV4IGM3YjVlZTgu LjM1YTVhNjcgMTAwNjQ0Ci0tLSBhL2RyaXZlcnMvcGh5L3F1YWxjb21tL0tjb25maWcKKysrIGIv ZHJpdmVycy9waHkvcXVhbGNvbW0vS2NvbmZpZwpAQCAtOTIsMyArOTIsMTQgQEAgY29uZmlnIFBI WV9RQ09NX1VTQl9IU19TTlBTXzI4Tk0KIAkgIEVuYWJsZSB0aGlzIHRvIHN1cHBvcnQgdGhlIFN5 bm9wc3lzIDI4bm0gRmVtdG8gVVNCIFBIWSBvbiBRdWFsY29tbQogCSAgY2hpcHMuIFRoaXMgZHJp dmVyIHN1cHBvcnRzIHRoZSBoaWdoLXNwZWVkIFBIWSB3aGljaCBpcyB1c3VhbGx5CiAJICBwYWly ZWQgd2l0aCBlaXRoZXIgdGhlIENoaXBJZGVhIG9yIFN5bm9wc3lzIERXQzMgVVNCIElQcyBvbiBN U00gU09Dcy4KKworY29uZmlnIFBIWV9RQ09NX1VTQl9TUworCXRyaXN0YXRlICJRdWFsY29tbSBV U0IgU1MgUEhZIGRyaXZlciIKKwlkZXBlbmRzIG9uIEFSQ0hfUUNPTSB8fCBDT01QSUxFX1RFU1QK KwlkZXBlbmRzIG9uIEVYVENPTiB8fCAhRVhUQ09OICMgaWYgRVhUQ09OPW0sIHRoaXMgY2Fubm90 IGJlIGJ1aWx0LWluCisJc2VsZWN0IEdFTkVSSUNfUEhZCisJaGVscAorCSAgRW5hYmxlIHRoaXMg dG8gc3VwcG9ydCB0aGUgU3VwZXItU3BlZWQgVVNCIHRyYW5zY2VpdmVyIG9uIFF1YWxjb21tCisJ ICBjaGlwcy4gVGhpcyBkcml2ZXIgc3VwcG9ydHMgdGhlIFBIWSB3aGljaCB1c2VzIHRoZSBRU0NS QVRDSC1iYXNlZAorCSAgcmVnaXN0ZXIgc2V0IGZvciBpdHMgY29udHJvbCBzZXF1ZW5jZXMsIG5v cm1hbGx5IHBhaXJlZCB3aXRoIG5ld2VyCisJICBEV0MzLWJhc2VkIFN1cGVyLVNwZWVkIGNvbnRy b2xsZXJzIG9uIFF1YWxjb21tIFNvQ3MuCmRpZmYgLS1naXQgYS9kcml2ZXJzL3BoeS9xdWFsY29t bS9NYWtlZmlsZSBiL2RyaXZlcnMvcGh5L3F1YWxjb21tL01ha2VmaWxlCmluZGV4IGRjMjM4ZDku LjcxNDkyNjEgMTAwNjQ0Ci0tLSBhL2RyaXZlcnMvcGh5L3F1YWxjb21tL01ha2VmaWxlCisrKyBi L2RyaXZlcnMvcGh5L3F1YWxjb21tL01ha2VmaWxlCkBAIC0xMCwzICsxMCw0IEBAIG9iai0kKENP TkZJR19QSFlfUUNPTV9VRlNfMjBOTSkJCSs9IHBoeS1xY29tLXVmcy1xbXAtMjBubS5vCiBvYmot JChDT05GSUdfUEhZX1FDT01fVVNCX0hTKSAJCSs9IHBoeS1xY29tLXVzYi1ocy5vCiBvYmotJChD T05GSUdfUEhZX1FDT01fVVNCX0hTSUMpIAkrPSBwaHktcWNvbS11c2ItaHNpYy5vCiBvYmotJChD T05GSUdfUEhZX1FDT01fVVNCX0hTX1NOUFNfMjhOTSkJKz0gcGh5LXFjb20tdXNiLWhzLXNuc3At MjhubS5vCitvYmotJChDT05GSUdfUEhZX1FDT01fVVNCX1NTKQkJKz0gcGh5LXFjb20tdXNiLXNz Lm8KZGlmZiAtLWdpdCBhL2RyaXZlcnMvcGh5L3F1YWxjb21tL3BoeS1xY29tLXVzYi1zcy5jIGIv ZHJpdmVycy9waHkvcXVhbGNvbW0vcGh5LXFjb20tdXNiLXNzLmMKbmV3IGZpbGUgbW9kZSAxMDA2 NDQKaW5kZXggMDAwMDAwMC4uZTZhZTk2ZQotLS0gL2Rldi9udWxsCisrKyBiL2RyaXZlcnMvcGh5 L3F1YWxjb21tL3BoeS1xY29tLXVzYi1zcy5jCkBAIC0wLDAgKzEsMzQ3IEBACisvLyBTUERYLUxp Y2Vuc2UtSWRlbnRpZmllcjogR1BMLTIuMAorLyoKKyAqIENvcHlyaWdodCAoYykgMjAxMi0yMDE0 LDIwMTcgVGhlIExpbnV4IEZvdW5kYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuCisgKiBDb3B5 cmlnaHQgKGMpIDIwMTgsIExpbmFybyBMaW1pdGVkCisgKi8KKworI2luY2x1ZGUgPGxpbnV4L2Ns ay5oPgorI2luY2x1ZGUgPGxpbnV4L2RlbGF5Lmg+CisjaW5jbHVkZSA8bGludXgvZXJyLmg+Cisj aW5jbHVkZSA8bGludXgvaW8uaD4KKyNpbmNsdWRlIDxsaW51eC9rZXJuZWwuaD4KKyNpbmNsdWRl IDxsaW51eC9tb2R1bGUuaD4KKyNpbmNsdWRlIDxsaW51eC9vZi5oPgorI2luY2x1ZGUgPGxpbnV4 L3BoeS9waHkuaD4KKyNpbmNsdWRlIDxsaW51eC9wbGF0Zm9ybV9kZXZpY2UuaD4KKyNpbmNsdWRl IDxsaW51eC9yZWd1bGF0b3IvY29uc3VtZXIuaD4KKyNpbmNsdWRlIDxsaW51eC9yZXNldC5oPgor I2luY2x1ZGUgPGxpbnV4L3NsYWIuaD4KKworI2RlZmluZSBQSFlfQ1RSTDAJCQkweDZDCisjZGVm aW5lIFBIWV9DVFJMMQkJCTB4NzAKKyNkZWZpbmUgUEhZX0NUUkwyCQkJMHg3NAorI2RlZmluZSBQ SFlfQ1RSTDQJCQkweDdDCisKKy8qIFBIWV9DVFJMIGJpdHMgKi8KKyNkZWZpbmUgUkVGX1BIWV9F TgkJCUJJVCgwKQorI2RlZmluZSBMQU5FMF9QV1JfT04JCQlCSVQoMikKKyNkZWZpbmUgU1dJX1BD U19DTEtfU0VMCQkJQklUKDQpCisjZGVmaW5lIFRTVF9QV1JfRE9XTgkJCUJJVCg0KQorI2RlZmlu ZSBQSFlfUkVTRVQJCQlCSVQoNykKKworZW51bSBwaHlfdmRkX2N0cmwgeyBFTkFCTEUsIERJU0FC TEUsIH07CitlbnVtIHBoeV9yZWd1bGF0b3IgeyBWREQsIFZEREExUDgsIH07CisKK3N0cnVjdCBz c3BoeV9wcml2IHsKKwl2b2lkIF9faW9tZW0gKmJhc2U7CisJc3RydWN0IGRldmljZSAqZGV2Owor CXN0cnVjdCByZXNldF9jb250cm9sICpyZXNldF9jb207CisJc3RydWN0IHJlc2V0X2NvbnRyb2wg KnJlc2V0X3BoeTsKKwlzdHJ1Y3QgcmVndWxhdG9yICp2YnVzOworCXN0cnVjdCByZWd1bGF0b3Jf YnVsa19kYXRhICpyZWdzOworCWludCBudW1fcmVnczsKKwlzdHJ1Y3QgY2xrX2J1bGtfZGF0YSAq Y2xrczsKKwlpbnQgbnVtX2Nsa3M7CisJZW51bSBwaHlfbW9kZSBtb2RlOworfTsKKworc3RhdGlj IGlubGluZSB2b2lkIHFjb21fc3NwaHlfdXBkYXRlbCh2b2lkIF9faW9tZW0gKmFkZHIsIHUzMiBt YXNrLCB1MzIgdmFsKQoreworCXdyaXRlbCgocmVhZGwoYWRkcikgJiB+bWFzaykgfCB2YWwsIGFk ZHIpOworfQorCitzdGF0aWMgaW5saW5lIGludCBxY29tX3NzcGh5X3ZidXNfZW5hYmxlKHN0cnVj dCByZWd1bGF0b3IgKnZidXMpCit7CisJcmV0dXJuICFyZWd1bGF0b3JfaXNfZW5hYmxlZCh2YnVz KSA/IHJlZ3VsYXRvcl9lbmFibGUodmJ1cykgOiAwOworfQorCitzdGF0aWMgaW5saW5lIGludCBx Y29tX3NzcGh5X3ZidXNfZGlzYWJsZShzdHJ1Y3QgcmVndWxhdG9yICp2YnVzKQoreworCXJldHVy biByZWd1bGF0b3JfaXNfZW5hYmxlZCh2YnVzKSA/IHJlZ3VsYXRvcl9kaXNhYmxlKHZidXMpIDog MDsKK30KKworc3RhdGljIGludCBxY29tX3NzcGh5X3ZkZF9jdHJsKHN0cnVjdCBzc3BoeV9wcml2 ICpwcml2LCBlbnVtIHBoeV92ZGRfY3RybCBjdHJsKQoreworCWNvbnN0IGludCB2ZGRfbWluID0g Y3RybCA9PSBFTkFCTEUgPyAxMDUwMDAwIDogMDsKKwljb25zdCBpbnQgdmRkX21heCA9IDEwNTAw MDA7CisJaW50IHJldDsKKworCXJldCA9IHJlZ3VsYXRvcl9zZXRfdm9sdGFnZShwcml2LT5yZWdz W1ZERF0uY29uc3VtZXIsIHZkZF9taW4sIHZkZF9tYXgpOworCWlmIChyZXQpCisJCWRldl9lcnIo cHJpdi0+ZGV2LCAiRmFpbGVkIHRvIHNldCByZWd1bGF0b3IgdmRkIHRvICVkXG4iLAorCQkJdmRk X21pbik7CisKKwlyZXR1cm4gcmV0OworfQorCitzdGF0aWMgaW50IHFjb21fc3NwaHlfdmJ1c19j dHJsKHN0cnVjdCByZWd1bGF0b3IgKnZidXMsIGVudW0gcGh5X21vZGUgbW9kZSkKK3sKKwlpZiAo IXZidXMpCisJCXJldHVybiAwOworCisJaWYgKG1vZGUgPT0gUEhZX01PREVfSU5WQUxJRCkKKwkJ cmV0dXJuIDA7CisKKwkvKiBnYWRnZXQgYXR0YWNoZWQgKi8KKwlpZiAobW9kZSA9PSBQSFlfTU9E RV9VU0JfSE9TVCkKKwkJcmV0dXJuIHFjb21fc3NwaHlfdmJ1c19lbmFibGUodmJ1cyk7CisKKwkv KiBVU0JfREVWSUNFOiBnYWRnZXQgcmVtb3ZlZDogZW5hYmxlIGRldGVjdGlvbiAqLworCXJldHVy biBxY29tX3NzcGh5X3ZidXNfZGlzYWJsZSh2YnVzKTsKK30KKworc3RhdGljIGludCBxY29tX3Nz cGh5X2RvX3Jlc2V0KHN0cnVjdCBzc3BoeV9wcml2ICpwcml2KQoreworCWludCByZXQ7CisKKwlp ZiAoIXByaXYtPnJlc2V0X2NvbSkgeworCQlxY29tX3NzcGh5X3VwZGF0ZWwocHJpdi0+YmFzZSAr IFBIWV9DVFJMMSwgUEhZX1JFU0VULAorCQkJCSAgIFBIWV9SRVNFVCk7CisJCXVzbGVlcF9yYW5n ZSgxMCwgMjApOworCQlxY29tX3NzcGh5X3VwZGF0ZWwocHJpdi0+YmFzZSArIFBIWV9DVFJMMSwg UEhZX1JFU0VULCAwKTsKKwl9IGVsc2UgeworCQlyZXQgPSByZXNldF9jb250cm9sX2Fzc2VydChw cml2LT5yZXNldF9jb20pOworCQlpZiAocmV0KSB7CisJCQlkZXZfZXJyKHByaXYtPmRldiwgIkZh aWxlZCB0byBhc3NlcnQgcmVzZXQgY29tXG4iKTsKKwkJCXJldHVybiByZXQ7CisJCX0KKworCQly ZXQgPSByZXNldF9jb250cm9sX2Fzc2VydChwcml2LT5yZXNldF9waHkpOworCQlpZiAocmV0KSB7 CisJCQlkZXZfZXJyKHByaXYtPmRldiwgIkZhaWxlZCB0byBhc3NlcnQgcmVzZXQgcGh5XG4iKTsK KwkJCXJldHVybiByZXQ7CisJCX0KKworCQl1c2xlZXBfcmFuZ2UoMTAsIDIwKTsKKworCQlyZXQg PSByZXNldF9jb250cm9sX2RlYXNzZXJ0KHByaXYtPnJlc2V0X2NvbSk7CisJCWlmIChyZXQpIHsK KwkJCWRldl9lcnIocHJpdi0+ZGV2LCAiRmFpbGVkIHRvIGRlYXNzZXJ0IHJlc2V0IGNvbVxuIik7 CisJCQlyZXR1cm4gcmV0OworCQl9CisKKwkJcmV0ID0gcmVzZXRfY29udHJvbF9kZWFzc2VydChw cml2LT5yZXNldF9waHkpOworCQlpZiAocmV0KSB7CisJCQlkZXZfZXJyKHByaXYtPmRldiwgIkZh aWxlZCB0byBkZWFzc2VydCByZXNldCBwaHlcbiIpOworCQkJcmV0dXJuIHJldDsKKwkJfQorCX0K KworCXJldHVybiAwOworfQorCitzdGF0aWMgaW50IHFjb21fc3NwaHlfcG93ZXJfb24oc3RydWN0 IHBoeSAqcGh5KQoreworCXN0cnVjdCBzc3BoeV9wcml2ICpwcml2ID0gcGh5X2dldF9kcnZkYXRh KHBoeSk7CisJaW50IHJldDsKKworCXJldCA9IHFjb21fc3NwaHlfdmRkX2N0cmwocHJpdiwgRU5B QkxFKTsKKwlpZiAocmV0KQorCQlyZXR1cm4gcmV0OworCisJcmV0ID0gcmVndWxhdG9yX2J1bGtf ZW5hYmxlKHByaXYtPm51bV9yZWdzLCBwcml2LT5yZWdzKTsKKwlpZiAocmV0KQorCQlnb3RvIGVy cjE7CisKKwlyZXQgPSBjbGtfYnVsa19wcmVwYXJlX2VuYWJsZShwcml2LT5udW1fY2xrcywgcHJp di0+Y2xrcyk7CisJaWYgKHJldCkKKwkJZ290byBlcnIyOworCisJcmV0ID0gcWNvbV9zc3BoeV92 YnVzX2N0cmwocHJpdi0+dmJ1cywgcHJpdi0+bW9kZSk7CisJaWYgKHJldCkKKwkJZ290byBlcnIz OworCisJcmV0ID0gcWNvbV9zc3BoeV9kb19yZXNldChwcml2KTsKKwlpZiAocmV0KQorCQlnb3Rv IGVycjQ7CisKKwl3cml0ZWIoU1dJX1BDU19DTEtfU0VMLCBwcml2LT5iYXNlICsgUEhZX0NUUkww KTsKKwlxY29tX3NzcGh5X3VwZGF0ZWwocHJpdi0+YmFzZSArIFBIWV9DVFJMNCwgTEFORTBfUFdS X09OLCBMQU5FMF9QV1JfT04pOworCXFjb21fc3NwaHlfdXBkYXRlbChwcml2LT5iYXNlICsgUEhZ X0NUUkwyLCBSRUZfUEhZX0VOLCBSRUZfUEhZX0VOKTsKKwlxY29tX3NzcGh5X3VwZGF0ZWwocHJp di0+YmFzZSArIFBIWV9DVFJMNCwgVFNUX1BXUl9ET1dOLCAwKTsKKworCXJldHVybiAwOworZXJy NDoKKwlpZiAocHJpdi0+dmJ1cyAmJiBwcml2LT5tb2RlICE9IFBIWV9NT0RFX0lOVkFMSUQpCisJ CXFjb21fc3NwaHlfdmJ1c19kaXNhYmxlKHByaXYtPnZidXMpOworZXJyMzoKKwljbGtfYnVsa19k aXNhYmxlX3VucHJlcGFyZShwcml2LT5udW1fY2xrcywgcHJpdi0+Y2xrcyk7CitlcnIyOgorCXJl Z3VsYXRvcl9idWxrX2Rpc2FibGUocHJpdi0+bnVtX3JlZ3MsIHByaXYtPnJlZ3MpOworZXJyMToK KwlxY29tX3NzcGh5X3ZkZF9jdHJsKHByaXYsIERJU0FCTEUpOworCisJcmV0dXJuIHJldDsKK30K Kworc3RhdGljIGludCBxY29tX3NzcGh5X3Bvd2VyX29mZihzdHJ1Y3QgcGh5ICpwaHkpCit7CisJ c3RydWN0IHNzcGh5X3ByaXYgKnByaXYgPSBwaHlfZ2V0X2RydmRhdGEocGh5KTsKKworCXFjb21f c3NwaHlfdXBkYXRlbChwcml2LT5iYXNlICsgUEhZX0NUUkw0LCBMQU5FMF9QV1JfT04sIDApOwor CXFjb21fc3NwaHlfdXBkYXRlbChwcml2LT5iYXNlICsgUEhZX0NUUkwyLCBSRUZfUEhZX0VOLCAw KTsKKwlxY29tX3NzcGh5X3VwZGF0ZWwocHJpdi0+YmFzZSArIFBIWV9DVFJMNCwgVFNUX1BXUl9E T1dOLCBUU1RfUFdSX0RPV04pOworCisJY2xrX2J1bGtfZGlzYWJsZV91bnByZXBhcmUocHJpdi0+ bnVtX2Nsa3MsIHByaXYtPmNsa3MpOworCXJlZ3VsYXRvcl9idWxrX2Rpc2FibGUocHJpdi0+bnVt X3JlZ3MsIHByaXYtPnJlZ3MpOworCisJaWYgKHByaXYtPnZidXMgJiYgcHJpdi0+bW9kZSAhPSBQ SFlfTU9ERV9JTlZBTElEKQorCQlxY29tX3NzcGh5X3ZidXNfZGlzYWJsZShwcml2LT52YnVzKTsK KworCXFjb21fc3NwaHlfdmRkX2N0cmwocHJpdiwgRElTQUJMRSk7CisKKwlyZXR1cm4gMDsKK30K Kworc3RhdGljIGludCBxY29tX3NzcGh5X2luaXRfY2xvY2soc3RydWN0IHNzcGh5X3ByaXYgKnBy aXYpCit7CisJY29uc3QgY2hhciAqIGNvbnN0IGNsa19pZFtdID0geyAicmVmIiwgInBoeSIsICJw aXBlIiwgfTsKKwlpbnQgaTsKKworCXByaXYtPm51bV9jbGtzID0gQVJSQVlfU0laRShjbGtfaWQp OworCXByaXYtPmNsa3MgPSBkZXZtX2tjYWxsb2MocHJpdi0+ZGV2LCBwcml2LT5udW1fY2xrcywK KwkJCQkgIHNpemVvZigqcHJpdi0+Y2xrcyksIEdGUF9LRVJORUwpOworCWlmICghcHJpdi0+Y2xr cykKKwkJcmV0dXJuIC1FTk9NRU07CisKKwlmb3IgKGkgPSAwOyBpIDwgcHJpdi0+bnVtX2Nsa3M7 IGkrKykKKwkJcHJpdi0+Y2xrc1tpXS5pZCA9IGNsa19pZFtpXTsKKworCXJldHVybiBkZXZtX2Ns a19idWxrX2dldChwcml2LT5kZXYsIHByaXYtPm51bV9jbGtzLCBwcml2LT5jbGtzKTsKK30KKwor c3RhdGljIGludCBxY29tX3NzcGh5X2luaXRfcmVndWxhdG9yKHN0cnVjdCBzc3BoeV9wcml2ICpw cml2KQoreworCWNvbnN0IGNoYXIgKiBjb25zdCByZWdfc3VwcGxpZXNbXSA9IHsKKwkJW1ZERF0g PSAidmRkIiwKKwkJW1ZEREExUDhdID0gInZkZGExcDgiLAorCX07CisJaW50IHJldCwgaTsKKwor CXByaXYtPm51bV9yZWdzID0gQVJSQVlfU0laRShyZWdfc3VwcGxpZXMpOworCXByaXYtPnJlZ3Mg PSBkZXZtX2tjYWxsb2MocHJpdi0+ZGV2LCBwcml2LT5udW1fcmVncywKKwkJCQkgIHNpemVvZigq cHJpdi0+cmVncyksIEdGUF9LRVJORUwpOworCWlmICghcHJpdi0+cmVncykKKwkJcmV0dXJuIC1F Tk9NRU07CisKKwlmb3IgKGkgPSAwOyBpIDwgcHJpdi0+bnVtX3JlZ3M7IGkrKykKKwkJcHJpdi0+ cmVnc1tpXS5zdXBwbHkgPSByZWdfc3VwcGxpZXNbaV07CisKKwlyZXQgPSBkZXZtX3JlZ3VsYXRv cl9idWxrX2dldChwcml2LT5kZXYsIHByaXYtPm51bV9yZWdzLCBwcml2LT5yZWdzKTsKKwlpZiAo cmV0KQorCQlyZXR1cm4gcmV0OworCisJcHJpdi0+dmJ1cyA9IGRldm1fcmVndWxhdG9yX2dldF9v cHRpb25hbChwcml2LT5kZXYsICJ2YnVzIik7CisJaWYgKElTX0VSUihwcml2LT52YnVzKSkKKwkJ cmV0dXJuIFBUUl9FUlIocHJpdi0+dmJ1cyk7CisKKwlyZXR1cm4gMDsKK30KKworc3RhdGljIGlu dCBxY29tX3NzcGh5X2luaXRfcmVzZXQoc3RydWN0IHNzcGh5X3ByaXYgKnByaXYpCit7CisJcHJp di0+cmVzZXRfY29tID0gZGV2bV9yZXNldF9jb250cm9sX2dldF9vcHRpb25hbChwcml2LT5kZXYs ICJjb20iKTsKKwlpZiAoSVNfRVJSKHByaXYtPnJlc2V0X2NvbSkpIHsKKwkJZGV2X2Vycihwcml2 LT5kZXYsICJGYWlsZWQgdG8gZ2V0IHJlc2V0IGNvbnRyb2wgY29tXG4iKTsKKwkJcmV0dXJuIFBU Ul9FUlIocHJpdi0+cmVzZXRfY29tKTsKKwl9CisKKwlpZiAocHJpdi0+cmVzZXRfY29tKSB7CisJ CS8qIGlmIHJlc2V0X2NvbSBpcyBwcmVzZW50LCByZXNldF9waHkgaXMgbm8gbG9uZ2VyIG9wdGlv bmFsICovCisJCXByaXYtPnJlc2V0X3BoeSA9IGRldm1fcmVzZXRfY29udHJvbF9nZXQocHJpdi0+ ZGV2LCAicGh5Iik7CisJCWlmIChJU19FUlIocHJpdi0+cmVzZXRfcGh5KSkgeworCQkJZGV2X2Vy cihwcml2LT5kZXYsICJGYWlsZWQgdG8gZ2V0IHJlc2V0IGNvbnRyb2wgcGh5XG4iKTsKKwkJCXJl dHVybiBQVFJfRVJSKHByaXYtPnJlc2V0X3BoeSk7CisJCX0KKwl9CisKKwlyZXR1cm4gMDsKK30K Kworc3RhdGljIGludCBxY29tX3NzcGh5X3NldF9tb2RlKHN0cnVjdCBwaHkgKnBoeSwgZW51bSBw aHlfbW9kZSBtb2RlLCBpbnQgc3VibW9kZSkKK3sKKwlzdHJ1Y3Qgc3NwaHlfcHJpdiAqcHJpdiA9 IHBoeV9nZXRfZHJ2ZGF0YShwaHkpOworCisJaWYgKCFwcml2LT52YnVzKQorCQlyZXR1cm4gMDsK KworCWlmIChtb2RlICE9IFBIWV9NT0RFX1VTQl9IT1NUICYmIG1vZGUgIT0gUEhZX01PREVfVVNC X0RFVklDRSkKKwkJcmV0dXJuIC1FSU5WQUw7CisKKwlwcml2LT5tb2RlID0gbW9kZTsKKworCWRl dl9kYmcocHJpdi0+ZGV2LCAibW9kZSAlZCIsIG1vZGUpOworCisJcmV0dXJuIHFjb21fc3NwaHlf dmJ1c19jdHJsKHByaXYtPnZidXMsIHByaXYtPm1vZGUpOworfQorCitzdGF0aWMgY29uc3Qgc3Ry dWN0IHBoeV9vcHMgcWNvbV9zc3BoeV9vcHMgPSB7CisJLnNldF9tb2RlID0gcWNvbV9zc3BoeV9z ZXRfbW9kZSwKKwkucG93ZXJfb2ZmID0gcWNvbV9zc3BoeV9wb3dlcl9vZmYsCisJLnBvd2VyX29u ID0gcWNvbV9zc3BoeV9wb3dlcl9vbiwKKwkub3duZXIgPSBUSElTX01PRFVMRSwKK307CisKK3N0 YXRpYyBpbnQgcWNvbV9zc3BoeV9wcm9iZShzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNlICpwZGV2KQor eworCXN0cnVjdCBkZXZpY2UgKmRldiA9ICZwZGV2LT5kZXY7CisJc3RydWN0IHBoeV9wcm92aWRl ciAqcHJvdmlkZXI7CisJc3RydWN0IHNzcGh5X3ByaXYgKnByaXY7CisJc3RydWN0IHJlc291cmNl ICpyZXM7CisJc3RydWN0IHBoeSAqcGh5OworCWludCByZXQ7CisKKwlwcml2ID0gZGV2bV9remFs bG9jKGRldiwgc2l6ZW9mKHN0cnVjdCBzc3BoeV9wcml2KSwgR0ZQX0tFUk5FTCk7CisJaWYgKCFw cml2KQorCQlyZXR1cm4gLUVOT01FTTsKKworCXByaXYtPmRldiA9IGRldjsKKwlwcml2LT5tb2Rl ID0gUEhZX01PREVfSU5WQUxJRDsKKworCXJlcyA9IHBsYXRmb3JtX2dldF9yZXNvdXJjZShwZGV2 LCBJT1JFU09VUkNFX01FTSwgMCk7CisJcHJpdi0+YmFzZSA9IGRldm1faW9yZW1hcF9yZXNvdXJj ZShkZXYsIHJlcyk7CisJaWYgKElTX0VSUihwcml2LT5iYXNlKSkKKwkJcmV0dXJuIFBUUl9FUlIo cHJpdi0+YmFzZSk7CisKKwlyZXQgPSBxY29tX3NzcGh5X2luaXRfY2xvY2socHJpdik7CisJaWYg KHJldCkKKwkJcmV0dXJuIHJldDsKKworCXJldCA9IHFjb21fc3NwaHlfaW5pdF9yZXNldChwcml2 KTsKKwlpZiAocmV0KQorCQlyZXR1cm4gcmV0OworCisJcmV0ID0gcWNvbV9zc3BoeV9pbml0X3Jl Z3VsYXRvcihwcml2KTsKKwlpZiAocmV0KQorCQlyZXR1cm4gcmV0OworCisJcGh5ID0gZGV2bV9w aHlfY3JlYXRlKGRldiwgZGV2LT5vZl9ub2RlLCAmcWNvbV9zc3BoeV9vcHMpOworCWlmIChJU19F UlIocGh5KSkgeworCQlkZXZfZXJyKGRldiwgIkZhaWxlZCB0byBjcmVhdGUgdGhlIFNTIHBoeVxu Iik7CisJCXJldHVybiBQVFJfRVJSKHBoeSk7CisJfQorCisJcGh5X3NldF9kcnZkYXRhKHBoeSwg cHJpdik7CisKKwlwcm92aWRlciA9IGRldm1fb2ZfcGh5X3Byb3ZpZGVyX3JlZ2lzdGVyKGRldiwg b2ZfcGh5X3NpbXBsZV94bGF0ZSk7CisKKwlyZXR1cm4gUFRSX0VSUl9PUl9aRVJPKHByb3ZpZGVy KTsKK30KKworc3RhdGljIGNvbnN0IHN0cnVjdCBvZl9kZXZpY2VfaWQgcWNvbV9zc3BoeV9tYXRj aFtdID0geworCXsgLmNvbXBhdGlibGUgPSAicWNvbSx1c2Itc3NwaHkiLCB9LAorCXsgfSwKK307 CitNT0RVTEVfREVWSUNFX1RBQkxFKG9mLCBxY29tX3NzcGh5X21hdGNoKTsKKworc3RhdGljIHN0 cnVjdCBwbGF0Zm9ybV9kcml2ZXIgcWNvbV9zc3BoeV9kcml2ZXIgPSB7CisJLnByb2JlCQk9IHFj b21fc3NwaHlfcHJvYmUsCisJLmRyaXZlciA9IHsKKwkJLm5hbWUJPSAicWNvbV91c2Jfc3NwaHki LAorCQkub2ZfbWF0Y2hfdGFibGUgPSBxY29tX3NzcGh5X21hdGNoLAorCX0sCit9OworbW9kdWxl X3BsYXRmb3JtX2RyaXZlcihxY29tX3NzcGh5X2RyaXZlcik7CisKK01PRFVMRV9ERVNDUklQVElP TigiUXVhbGNvbW0gU3VwZXItU3BlZWQgVVNCIFBIWSBkcml2ZXIiKTsKK01PRFVMRV9MSUNFTlNF KCJHUEwgdjIiKTsK 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=-9.0 required=3.0 tests=DKIMWL_WL_HIGH,DKIM_SIGNED, DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT 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 D47E0C169C4 for ; Tue, 29 Jan 2019 11:36:05 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (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 877C720844 for ; Tue, 29 Jan 2019 11:36:05 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="UZ5Ql97Q"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=linaro.org header.i=@linaro.org header.b="W3QVl+RY" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 877C720844 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=linaro.org Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+infradead-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=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=iTI27r5L3M9hXzpNcVAmsOUzvnomwqvh1ziNucppOIo=; b=UZ5Ql97QXXa6ac9kbbCq1vJtL2 2xlTK1/h1vJFGI4lYW2p4x2WmP6SGfnYZwzgc0s4DkLu5df9scYwwGS+YaqP7z3pY42mkMI9EHjt5 1c6v1tYXlDFeD1DG01J2oy1IP0BcECOfpdsxYAvZJptYRS7h4RCmW+gpbr9cqkJICqnZBWSkscUO6 e5su9ZqiL6017FP+GAImLSXjQOLPm6ZN0mSi9uOlkf/OmKWZx1NTBFLKaveVAr2CUctoAGMb4guk1 C0ZS0JO1KkmpcEJk9ynSO9CzuYqM4oV5r3PyTQR7P4EOC3/0PP0ILxuyXkYZMwJf8d0O88BwAi744 kUFXo3ww==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1goRgL-0008H4-S8; Tue, 29 Jan 2019 11:35:57 +0000 Received: from mail-wr1-x443.google.com ([2a00:1450:4864:20::443]) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1goRfo-0007jG-0F for linux-arm-kernel@lists.infradead.org; Tue, 29 Jan 2019 11:35:32 +0000 Received: by mail-wr1-x443.google.com with SMTP id r10so21619276wrs.10 for ; Tue, 29 Jan 2019 03:35:23 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=VBrpJcJs752W++ic9rn3GaeRCbiL/4SmAU6bli7+VYk=; b=W3QVl+RYCf6dOsZsWrtHzzBIfeTbHxubg4r1eqqud9cuKvcNxKo/2XqVjCz0vx3HKC O66PDhKDpyYG9oa63RPNRupINT9f6gi7VDRoSA4RJ23/pNdlAkhJQBCSLB+9SNzunRSf 1g2miB73Qw9GdPGzLUoElnTxJPdT1YpbeWwEU= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=VBrpJcJs752W++ic9rn3GaeRCbiL/4SmAU6bli7+VYk=; b=Z25FW7d2DNc6SJJdOZYSxAS9zJDtVuR4EriL6XSaGDOZ+4hH199SnvZ4LG9oyv5bCO WqVppHlHy7b6OG599aCBpE51/TPUkhD4LEypVHd1Sk7yi5q/B171uleKGaiUWKFyp25/ o6icAW8jB6QPt1ihDuiTHwadP1Fd73APgWE/SP8M+cf5d1ICTRgUjRynnZye6mHxGBJ4 /j7EJyvstnM8lhJeejYnOLG71AItyD66l2DFNs9UV6Ta0ABi82fHZtv2msbsjBLK0v+f EfHdSAIOkWvH7kDdthhE+Mge4VWpF4ceBovwOVpM0d5xCpDViw13n9z83hPBVk3/vAsL rHjg== X-Gm-Message-State: AJcUukd812VihTuntxvC8e77fgpxWwSulUhpQ1MJVbCfIBNGmB7NFzAj 3Sa5YFEVEmplatYtJDbhz7EMSg== X-Google-Smtp-Source: ALg8bN5hWgbVM4nxHAu3jl35edxuRl9813cf11QPZPQ66bN9YwVXUk9mctVm9W83MFNPyOYzjmrmuw== X-Received: by 2002:adf:afdc:: with SMTP id y28mr24857802wrd.275.1548761722001; Tue, 29 Jan 2019 03:35:22 -0800 (PST) Received: from localhost.localdomain (233.red-81-47-145.staticip.rima-tde.net. [81.47.145.233]) by smtp.gmail.com with ESMTPSA id i192sm1960129wmg.7.2019.01.29.03.35.20 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 29 Jan 2019 03:35:21 -0800 (PST) From: Jorge Ramirez-Ortiz To: jorge.ramirez-ortiz@linaro.org, gregkh@linuxfoundation.org, mark.rutland@arm.com, kishon@ti.com, jackp@codeaurora.org, andy.gross@linaro.org, swboyd@chromium.org Subject: [PATCH v2 2/2] phy: qualcomm: usb: Add Super-Speed PHY driver Date: Tue, 29 Jan 2019 12:35:15 +0100 Message-Id: <1548761715-4004-3-git-send-email-jorge.ramirez-ortiz@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1548761715-4004-1-git-send-email-jorge.ramirez-ortiz@linaro.org> References: <1548761715-4004-1-git-send-email-jorge.ramirez-ortiz@linaro.org> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190129_033524_042717_0CE8C54B X-CRM114-Status: GOOD ( 20.74 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: devicetree@vger.kernel.org, linux-arm-msm@vger.kernel.org, linux-usb@vger.kernel.org, khasim.mohammed@linaro.org, linux-kernel@vger.kernel.org, bjorn.andersson@linaro.org, vkoul@kernel.org, shawn.guo@linaro.org, linux-arm-kernel@lists.infradead.org MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+infradead-linux-arm-kernel=archiver.kernel.org@lists.infradead.org Driver to control the Synopsys SS PHY 1.0.0 implemeneted in QCS404 Based on Sriharsha Allenki's original code. Signed-off-by: Jorge Ramirez-Ortiz --- drivers/phy/qualcomm/Kconfig | 11 ++ drivers/phy/qualcomm/Makefile | 1 + drivers/phy/qualcomm/phy-qcom-usb-ss.c | 347 +++++++++++++++++++++++++++++++++ 3 files changed, 359 insertions(+) create mode 100644 drivers/phy/qualcomm/phy-qcom-usb-ss.c diff --git a/drivers/phy/qualcomm/Kconfig b/drivers/phy/qualcomm/Kconfig index c7b5ee8..35a5a67 100644 --- a/drivers/phy/qualcomm/Kconfig +++ b/drivers/phy/qualcomm/Kconfig @@ -92,3 +92,14 @@ config PHY_QCOM_USB_HS_SNPS_28NM Enable this to support the Synopsys 28nm Femto USB PHY on Qualcomm chips. This driver supports the high-speed PHY which is usually paired with either the ChipIdea or Synopsys DWC3 USB IPs on MSM SOCs. + +config PHY_QCOM_USB_SS + tristate "Qualcomm USB SS PHY driver" + depends on ARCH_QCOM || COMPILE_TEST + depends on EXTCON || !EXTCON # if EXTCON=m, this cannot be built-in + select GENERIC_PHY + help + Enable this to support the Super-Speed USB transceiver on Qualcomm + chips. This driver supports the PHY which uses the QSCRATCH-based + register set for its control sequences, normally paired with newer + DWC3-based Super-Speed controllers on Qualcomm SoCs. diff --git a/drivers/phy/qualcomm/Makefile b/drivers/phy/qualcomm/Makefile index dc238d9..7149261 100644 --- a/drivers/phy/qualcomm/Makefile +++ b/drivers/phy/qualcomm/Makefile @@ -10,3 +10,4 @@ obj-$(CONFIG_PHY_QCOM_UFS_20NM) += phy-qcom-ufs-qmp-20nm.o obj-$(CONFIG_PHY_QCOM_USB_HS) += phy-qcom-usb-hs.o obj-$(CONFIG_PHY_QCOM_USB_HSIC) += phy-qcom-usb-hsic.o obj-$(CONFIG_PHY_QCOM_USB_HS_SNPS_28NM) += phy-qcom-usb-hs-snsp-28nm.o +obj-$(CONFIG_PHY_QCOM_USB_SS) += phy-qcom-usb-ss.o diff --git a/drivers/phy/qualcomm/phy-qcom-usb-ss.c b/drivers/phy/qualcomm/phy-qcom-usb-ss.c new file mode 100644 index 0000000..e6ae96e --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-usb-ss.c @@ -0,0 +1,347 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2012-2014,2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2018, Linaro Limited + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PHY_CTRL0 0x6C +#define PHY_CTRL1 0x70 +#define PHY_CTRL2 0x74 +#define PHY_CTRL4 0x7C + +/* PHY_CTRL bits */ +#define REF_PHY_EN BIT(0) +#define LANE0_PWR_ON BIT(2) +#define SWI_PCS_CLK_SEL BIT(4) +#define TST_PWR_DOWN BIT(4) +#define PHY_RESET BIT(7) + +enum phy_vdd_ctrl { ENABLE, DISABLE, }; +enum phy_regulator { VDD, VDDA1P8, }; + +struct ssphy_priv { + void __iomem *base; + struct device *dev; + struct reset_control *reset_com; + struct reset_control *reset_phy; + struct regulator *vbus; + struct regulator_bulk_data *regs; + int num_regs; + struct clk_bulk_data *clks; + int num_clks; + enum phy_mode mode; +}; + +static inline void qcom_ssphy_updatel(void __iomem *addr, u32 mask, u32 val) +{ + writel((readl(addr) & ~mask) | val, addr); +} + +static inline int qcom_ssphy_vbus_enable(struct regulator *vbus) +{ + return !regulator_is_enabled(vbus) ? regulator_enable(vbus) : 0; +} + +static inline int qcom_ssphy_vbus_disable(struct regulator *vbus) +{ + return regulator_is_enabled(vbus) ? regulator_disable(vbus) : 0; +} + +static int qcom_ssphy_vdd_ctrl(struct ssphy_priv *priv, enum phy_vdd_ctrl ctrl) +{ + const int vdd_min = ctrl == ENABLE ? 1050000 : 0; + const int vdd_max = 1050000; + int ret; + + ret = regulator_set_voltage(priv->regs[VDD].consumer, vdd_min, vdd_max); + if (ret) + dev_err(priv->dev, "Failed to set regulator vdd to %d\n", + vdd_min); + + return ret; +} + +static int qcom_ssphy_vbus_ctrl(struct regulator *vbus, enum phy_mode mode) +{ + if (!vbus) + return 0; + + if (mode == PHY_MODE_INVALID) + return 0; + + /* gadget attached */ + if (mode == PHY_MODE_USB_HOST) + return qcom_ssphy_vbus_enable(vbus); + + /* USB_DEVICE: gadget removed: enable detection */ + return qcom_ssphy_vbus_disable(vbus); +} + +static int qcom_ssphy_do_reset(struct ssphy_priv *priv) +{ + int ret; + + if (!priv->reset_com) { + qcom_ssphy_updatel(priv->base + PHY_CTRL1, PHY_RESET, + PHY_RESET); + usleep_range(10, 20); + qcom_ssphy_updatel(priv->base + PHY_CTRL1, PHY_RESET, 0); + } else { + ret = reset_control_assert(priv->reset_com); + if (ret) { + dev_err(priv->dev, "Failed to assert reset com\n"); + return ret; + } + + ret = reset_control_assert(priv->reset_phy); + if (ret) { + dev_err(priv->dev, "Failed to assert reset phy\n"); + return ret; + } + + usleep_range(10, 20); + + ret = reset_control_deassert(priv->reset_com); + if (ret) { + dev_err(priv->dev, "Failed to deassert reset com\n"); + return ret; + } + + ret = reset_control_deassert(priv->reset_phy); + if (ret) { + dev_err(priv->dev, "Failed to deassert reset phy\n"); + return ret; + } + } + + return 0; +} + +static int qcom_ssphy_power_on(struct phy *phy) +{ + struct ssphy_priv *priv = phy_get_drvdata(phy); + int ret; + + ret = qcom_ssphy_vdd_ctrl(priv, ENABLE); + if (ret) + return ret; + + ret = regulator_bulk_enable(priv->num_regs, priv->regs); + if (ret) + goto err1; + + ret = clk_bulk_prepare_enable(priv->num_clks, priv->clks); + if (ret) + goto err2; + + ret = qcom_ssphy_vbus_ctrl(priv->vbus, priv->mode); + if (ret) + goto err3; + + ret = qcom_ssphy_do_reset(priv); + if (ret) + goto err4; + + writeb(SWI_PCS_CLK_SEL, priv->base + PHY_CTRL0); + qcom_ssphy_updatel(priv->base + PHY_CTRL4, LANE0_PWR_ON, LANE0_PWR_ON); + qcom_ssphy_updatel(priv->base + PHY_CTRL2, REF_PHY_EN, REF_PHY_EN); + qcom_ssphy_updatel(priv->base + PHY_CTRL4, TST_PWR_DOWN, 0); + + return 0; +err4: + if (priv->vbus && priv->mode != PHY_MODE_INVALID) + qcom_ssphy_vbus_disable(priv->vbus); +err3: + clk_bulk_disable_unprepare(priv->num_clks, priv->clks); +err2: + regulator_bulk_disable(priv->num_regs, priv->regs); +err1: + qcom_ssphy_vdd_ctrl(priv, DISABLE); + + return ret; +} + +static int qcom_ssphy_power_off(struct phy *phy) +{ + struct ssphy_priv *priv = phy_get_drvdata(phy); + + qcom_ssphy_updatel(priv->base + PHY_CTRL4, LANE0_PWR_ON, 0); + qcom_ssphy_updatel(priv->base + PHY_CTRL2, REF_PHY_EN, 0); + qcom_ssphy_updatel(priv->base + PHY_CTRL4, TST_PWR_DOWN, TST_PWR_DOWN); + + clk_bulk_disable_unprepare(priv->num_clks, priv->clks); + regulator_bulk_disable(priv->num_regs, priv->regs); + + if (priv->vbus && priv->mode != PHY_MODE_INVALID) + qcom_ssphy_vbus_disable(priv->vbus); + + qcom_ssphy_vdd_ctrl(priv, DISABLE); + + return 0; +} + +static int qcom_ssphy_init_clock(struct ssphy_priv *priv) +{ + const char * const clk_id[] = { "ref", "phy", "pipe", }; + int i; + + priv->num_clks = ARRAY_SIZE(clk_id); + priv->clks = devm_kcalloc(priv->dev, priv->num_clks, + sizeof(*priv->clks), GFP_KERNEL); + if (!priv->clks) + return -ENOMEM; + + for (i = 0; i < priv->num_clks; i++) + priv->clks[i].id = clk_id[i]; + + return devm_clk_bulk_get(priv->dev, priv->num_clks, priv->clks); +} + +static int qcom_ssphy_init_regulator(struct ssphy_priv *priv) +{ + const char * const reg_supplies[] = { + [VDD] = "vdd", + [VDDA1P8] = "vdda1p8", + }; + int ret, i; + + priv->num_regs = ARRAY_SIZE(reg_supplies); + priv->regs = devm_kcalloc(priv->dev, priv->num_regs, + sizeof(*priv->regs), GFP_KERNEL); + if (!priv->regs) + return -ENOMEM; + + for (i = 0; i < priv->num_regs; i++) + priv->regs[i].supply = reg_supplies[i]; + + ret = devm_regulator_bulk_get(priv->dev, priv->num_regs, priv->regs); + if (ret) + return ret; + + priv->vbus = devm_regulator_get_optional(priv->dev, "vbus"); + if (IS_ERR(priv->vbus)) + return PTR_ERR(priv->vbus); + + return 0; +} + +static int qcom_ssphy_init_reset(struct ssphy_priv *priv) +{ + priv->reset_com = devm_reset_control_get_optional(priv->dev, "com"); + if (IS_ERR(priv->reset_com)) { + dev_err(priv->dev, "Failed to get reset control com\n"); + return PTR_ERR(priv->reset_com); + } + + if (priv->reset_com) { + /* if reset_com is present, reset_phy is no longer optional */ + priv->reset_phy = devm_reset_control_get(priv->dev, "phy"); + if (IS_ERR(priv->reset_phy)) { + dev_err(priv->dev, "Failed to get reset control phy\n"); + return PTR_ERR(priv->reset_phy); + } + } + + return 0; +} + +static int qcom_ssphy_set_mode(struct phy *phy, enum phy_mode mode, int submode) +{ + struct ssphy_priv *priv = phy_get_drvdata(phy); + + if (!priv->vbus) + return 0; + + if (mode != PHY_MODE_USB_HOST && mode != PHY_MODE_USB_DEVICE) + return -EINVAL; + + priv->mode = mode; + + dev_dbg(priv->dev, "mode %d", mode); + + return qcom_ssphy_vbus_ctrl(priv->vbus, priv->mode); +} + +static const struct phy_ops qcom_ssphy_ops = { + .set_mode = qcom_ssphy_set_mode, + .power_off = qcom_ssphy_power_off, + .power_on = qcom_ssphy_power_on, + .owner = THIS_MODULE, +}; + +static int qcom_ssphy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct phy_provider *provider; + struct ssphy_priv *priv; + struct resource *res; + struct phy *phy; + int ret; + + priv = devm_kzalloc(dev, sizeof(struct ssphy_priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = dev; + priv->mode = PHY_MODE_INVALID; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->base = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + ret = qcom_ssphy_init_clock(priv); + if (ret) + return ret; + + ret = qcom_ssphy_init_reset(priv); + if (ret) + return ret; + + ret = qcom_ssphy_init_regulator(priv); + if (ret) + return ret; + + phy = devm_phy_create(dev, dev->of_node, &qcom_ssphy_ops); + if (IS_ERR(phy)) { + dev_err(dev, "Failed to create the SS phy\n"); + return PTR_ERR(phy); + } + + phy_set_drvdata(phy, priv); + + provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(provider); +} + +static const struct of_device_id qcom_ssphy_match[] = { + { .compatible = "qcom,usb-ssphy", }, + { }, +}; +MODULE_DEVICE_TABLE(of, qcom_ssphy_match); + +static struct platform_driver qcom_ssphy_driver = { + .probe = qcom_ssphy_probe, + .driver = { + .name = "qcom_usb_ssphy", + .of_match_table = qcom_ssphy_match, + }, +}; +module_platform_driver(qcom_ssphy_driver); + +MODULE_DESCRIPTION("Qualcomm Super-Speed USB PHY driver"); +MODULE_LICENSE("GPL v2"); -- 2.7.4 _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel