[PATCH v2 0/3] usb: dwc3: support for Qualcomm DWC3 glue

2018-04-13 Thread Manu Gautam
Add separate dwc3-qcom glue driver for Qualcomm SOCs having dwc3 core.
It is needed to support peripheral mode.
Patches also add support to invoke PHY runtime PM functions on host
mode bus-suspend.

Changes since v1:
 - Move dwc3 core register accesses from glue driver to dwc3 core as
   per review comment from Felipe.
 - Addressed other review comments from Felipe and Rob.
 - Some other minor code changes related to redability.
 - Add reset_control assert in driver probe to ensure core registers
   are reset to POR value in case of any initalization by boot code. 

Manu Gautam (3):
  dt-bindings: usb: Update documentation for Qualcomm DWC3 driver
  usb: dwc3: Add Qualcomm DWC3 glue driver
  usb: dwc3: core: Suspend PHYs on runtime suspend in host mode

 .../devicetree/bindings/usb/qcom,dwc3.txt  |  78 ++-
 drivers/usb/dwc3/Kconfig   |  12 +
 drivers/usb/dwc3/Makefile  |   1 +
 drivers/usb/dwc3/core.c|  36 +-
 drivers/usb/dwc3/dwc3-of-simple.c  |   1 -
 drivers/usb/dwc3/dwc3-qcom.c   | 618 +
 6 files changed, 721 insertions(+), 25 deletions(-)
 create mode 100644 drivers/usb/dwc3/dwc3-qcom.c

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v2 3/3] usb: dwc3: core: Suspend PHYs on runtime suspend in host mode

2018-04-13 Thread Manu Gautam
Some PHY drivers (e.g. for Qualcomm QUSB2 and QMP PHYs) support
runtime PM to reduce PHY power consumption during bus_suspend.
Add changes to let core auto-suspend PHYs on host bus-suspend
using GUSB2PHYCFG register if needed for a platform. Also perform
PHYs runtime suspend/resume and let platform glue drivers e.g.
dwc3-qcom handle remote wakeup during bus suspend by waking up
devices on receiving wakeup event from PHY.

Signed-off-by: Manu Gautam 
---
 drivers/usb/dwc3/core.c | 36 +---
 1 file changed, 33 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index a15648d..449a098 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -1394,6 +1394,7 @@ static int dwc3_remove(struct platform_device *pdev)
 static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
 {
unsigned long   flags;
+   u32 reg;
 
switch (dwc->current_dr_role) {
case DWC3_GCTL_PRTCAP_DEVICE:
@@ -1403,9 +1404,25 @@ static int dwc3_suspend_common(struct dwc3 *dwc, 
pm_message_t msg)
dwc3_core_exit(dwc);
break;
case DWC3_GCTL_PRTCAP_HOST:
-   /* do nothing during host runtime_suspend */
-   if (!PMSG_IS_AUTO(msg))
+   if (!PMSG_IS_AUTO(msg)) {
dwc3_core_exit(dwc);
+   break;
+   }
+
+   /* Let controller to suspend HSPHY before PHY driver suspends */
+   if (dwc->dis_u2_susphy_quirk ||
+   dwc->dis_enblslpm_quirk) {
+   reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+   reg |=  DWC3_GUSB2PHYCFG_ENBLSLPM |
+   DWC3_GUSB2PHYCFG_SUSPHY;
+   dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+
+   /* Give some time for USB2 PHY to suspend */
+   usleep_range(5000, 6000);
+   }
+
+   phy_pm_runtime_put_sync(dwc->usb2_generic_phy);
+   phy_pm_runtime_put_sync(dwc->usb3_generic_phy);
break;
case DWC3_GCTL_PRTCAP_OTG:
/* do nothing during runtime_suspend */
@@ -1433,6 +1450,7 @@ static int dwc3_resume_common(struct dwc3 *dwc, 
pm_message_t msg)
 {
unsigned long   flags;
int ret;
+   u32 reg;
 
switch (dwc->current_dr_role) {
case DWC3_GCTL_PRTCAP_DEVICE:
@@ -1446,13 +1464,25 @@ static int dwc3_resume_common(struct dwc3 *dwc, 
pm_message_t msg)
spin_unlock_irqrestore(&dwc->lock, flags);
break;
case DWC3_GCTL_PRTCAP_HOST:
-   /* nothing to do on host runtime_resume */
if (!PMSG_IS_AUTO(msg)) {
ret = dwc3_core_init(dwc);
if (ret)
return ret;
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
+   break;
}
+   /* Restore GUSB2PHYCFG bits that were modified in suspend */
+   reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+   if (dwc->dis_u2_susphy_quirk)
+   reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
+
+   if (dwc->dis_enblslpm_quirk)
+   reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
+
+   dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+
+   phy_pm_runtime_get_sync(dwc->usb2_generic_phy);
+   phy_pm_runtime_get_sync(dwc->usb3_generic_phy);
break;
case DWC3_GCTL_PRTCAP_OTG:
/* nothing to do on runtime_resume */
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v2 2/3] usb: dwc3: Add Qualcomm DWC3 glue driver

2018-04-13 Thread Manu Gautam
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.
 - pwr_events_irq_stat support to check if USB2 PHY is in L2 state
   before glue driver proceeds with suspend.
 - Support for wakeup interrupts lines that are asserted whenever
   there is any wakeup event on USB3 or USB2 bus.
 - Support to replace pip3 clock going to DWC3 with utmi clock
   for hardware configuration where SSPHY is not used with DWC3.

Signed-off-by: Manu Gautam 
---
 drivers/usb/dwc3/Kconfig  |  12 +
 drivers/usb/dwc3/Makefile |   1 +
 drivers/usb/dwc3/dwc3-of-simple.c |   1 -
 drivers/usb/dwc3/dwc3-qcom.c  | 618 ++
 4 files changed, 631 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..451012e 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -106,4 +106,16 @@ config USB_DWC3_ST
  inside (i.e. STiH407).
  Say 'Y' or 'M' if you have one such device.
 
+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.
+ This driver also handles Qscratch wrapper which is needed
+ for peripheral mode support.
+ Say 'Y' or 'M' if you have one such device.
+
 endif
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
index 025bc68..5c07d8f 100644
--- a/drivers/usb/dwc3/Makefile
+++ b/drivers/usb/dwc3/Makefile
@@ -48,3 +48,4 @@ obj-$(CONFIG_USB_DWC3_PCI)+= dwc3-pci.o
 obj-$(CONFIG_USB_DWC3_KEYSTONE)+= dwc3-keystone.o
 obj-$(CONFIG_USB_DWC3_OF_SIMPLE)   += dwc3-of-simple.o
 obj-$(CONFIG_USB_DWC3_ST)  += dwc3-st.o
+obj-$(CONFIG_USB_DWC3_QCOM)+= 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 device *dev)
 };
 
 static const struct of_device_id of_dwc3_simple_match[] = {
-   { .compatible = "qcom,dwc3" },
{ .compatible = "rockchip,rk3399-dwc3" },
{ .compatible = "xlnx,zynqmp-dwc3" },
{ .compatible = "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 000..ecb2218
--- /dev/null
+++ b/drivers/usb/dwc3/dwc3-qcom.c
@@ -0,0 +1,618 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * Inspired by dwc3-of-simple.c
+ */
+#define DEBUG
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "core.h"
+
+/* USB QSCRATCH Hardware registers */
+#define QSCRATCH_HS_PHY_CTRL   0x10
+#define UTMI_OTG_VBUS_VALIDBIT(20)
+#define SW_SESSVLD_SEL BIT(28)
+
+#define QSCRATCH_SS_PHY_CTRL   0x30
+#define LANE0_PWR_PRESENT  BIT(24)
+
+#define QSCRATCH_GENERAL_CFG   0x08
+#define PIPE_UTMI_CLK_SEL  BIT(0)
+#define PIPE3_PHYSTATUS_SW BIT(3)
+#define PIPE_UTMI_CLK_DIS  BIT(8)
+
+#define PWR_EVNT_IRQ_STAT_REG  0x58
+#define PWR_EVNT_LPM_IN_L2_MASKBIT(4)
+#define PWR_EVNT_LPM_OUT_L2_MASK   BIT(5)
+
+struct dwc3_qcom {
+   struct device   *dev;
+   void __iomem*qscratch_base;
+   struct platform_device  *dwc3;
+   struct clk  **clks;
+   int num_clocks;
+   struct reset_control*resets;
+
+   int hs_phy_irq;
+   int dp_hs_phy_irq;
+   int dm_hs_phy_irq;
+   int ss_phy_irq;
+
+   struct extcon_dev   *edev;
+   struct extcon_dev   *host_edev;
+   struct notifier_block   vbus_nb;
+   struct notifier_block   host_nb;
+
+   enum usb_dr_modemode;
+   boolis_suspended;
+   boolpm_suspended;
+};
+
+static inli

[PATCH v2 1/3] dt-bindings: usb: Update documentation for Qualcomm DWC3 driver

2018-04-13 Thread Manu Gautam
Existing documentation has lot of incorrect information as it
was originally added for a driver that no longer exists.

Signed-off-by: Manu Gautam 
---
 .../devicetree/bindings/usb/qcom,dwc3.txt  | 78 --
 1 file changed, 57 insertions(+), 21 deletions(-)

diff --git a/Documentation/devicetree/bindings/usb/qcom,dwc3.txt 
b/Documentation/devicetree/bindings/usb/qcom,dwc3.txt
index bc8a2fa..fdc574a 100644
--- a/Documentation/devicetree/bindings/usb/qcom,dwc3.txt
+++ b/Documentation/devicetree/bindings/usb/qcom,dwc3.txt
@@ -1,54 +1,90 @@
 Qualcomm SuperSpeed DWC3 USB SoC controller
 
 Required properties:
-- compatible:  should contain "qcom,dwc3"
+- compatible:  should contain "qcom,dwc3"
+- reg: offset and length of register set for QSCRATCH wrapper
+- power-domains:   specifies a phandle to PM domain provider node
 - clocks:  A list of phandle + clock-specifier pairs for the
clocks listed in clock-names
-- clock-names: Should contain the following:
+- clock-names: Should contain the following:
   "core"   Master/Core clock, have to be >= 125 MHz for SS
operation and >= 60MHz for HS operation
+  "mock_utmi"  Mock utmi clock needed for ITP/SOF generation in
+   host mode. Its frequency should be 19.2MHz.
+  "sleep"  Sleep clock, used for wakeup when USB3 core goes
+   into low power mode (U3).
 
 Optional clocks:
   "iface"  System bus AXI clock.  Not present on all platforms
-  "sleep"  Sleep clock, used when USB3 core goes into low
-   power mode (U3).
+  "cfg_noc"System Config NOC clock. Not present on all platforms
+- assigned-clocks: should be:
+   MOCK_UTMI_CLK
+   MASTER_CLK
+- assigned-clock-rates: should be:
+19.2Mhz (19200) for MOCK_UTMI_CLK
+>=125Mhz (12500) for MASTER_CLK in SS mode
+>=60Mhz (6000) for MASTER_CLK in HS mode
+
+Optional properties:
+- resets:  list of phandle and reset specifier pairs
+- interrupts:  specifies interrupts from controller wrapper used
+   to wakeup from low power/susepnd state. Must contain
+   one or more entry for interrupt-names property
+- interrupt-names: Must include the following entries:
+   - "hs_phy_irq": The interrupt that is asserted when a
+  wakeup event is received on USB2 bus
+   - "ss_phy_irq": The interrupt that is asserted when a
+  wakeup event is received on USB3 bus
+   - "dm_hs_phy_irq" and "dp_hs_phy_irq": Separate
+  interrupts for any wakeup event on DM and DP lines
+- qcom,select-utmi-as-pipe-clk: if present, disable USB3 pipe_clk requirement.
+   Used when dwc3 operates without SSPHY and only
+   HS/FS/LS modes are supported.
 
 Required child node:
 A child node must exist to represent the core DWC3 IP block. The name of
 the node is not important. The content of the node is defined in dwc3.txt.
 
 Phy documentation is provided in the following places:
-Documentation/devicetree/bindings/phy/qcom-dwc3-usb-phy.txt
+Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt   - USB3 QMP PHY
+Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt - USB2 QUSB2 PHY
 
 Example device nodes:
 
hs_phy: phy@100f8800 {
-   compatible = "qcom,dwc3-hs-usb-phy";
-   reg = <0x100f8800 0x30>;
-   clocks = <&gcc USB30_0_UTMI_CLK>;
-   clock-names = "ref";
-   #phy-cells = <0>;
-
+   compatible = "qcom,qusb2-v2-phy";
+   ...
};
 
ss_phy: phy@100f8830 {
-   compatible = "qcom,dwc3-ss-usb-phy";
-   reg = <0x100f8830 0x30>;
-   clocks = <&gcc USB30_0_MASTER_CLK>;
-   clock-names = "ref";
-   #phy-cells = <0>;
-
+   compatible = "qcom,qmp-v3-usb3-phy";
+   ...
};
 
-   usb3_0: usb30@0 {
+   usb3_0: usb30@a6f8800 {
compatible = "qcom,dwc3";
+   reg = <0xa6f8800 0x400>;
#address-cells = <

Re: [PATCH v2 2/3] usb: dwc3: Add Qualcomm DWC3 glue driver

2018-04-13 Thread Manu Gautam
Hi Jack,


On 4/13/2018 11:03 PM, Jack Pham wrote:
> Hi Manu,
>
> On Fri, Apr 13, 2018 at 10:21:23PM +0530, Manu Gautam wrote:
>> 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.
>>  - pwr_events_irq_stat support to check if USB2 PHY is in L2 state
>>before glue driver proceeds with suspend.
>>  - Support for wakeup interrupts lines that are asserted whenever
>>there is any wakeup event on USB3 or USB2 bus.
>>  - Support to replace pip3 clock going to DWC3 with utmi clock
>>for hardware configuration where SSPHY is not used with DWC3.
>>
>> Signed-off-by: Manu Gautam 
> 
>
>> +static int dwc3_qcom_register_extcon(struct dwc3_qcom *qcom)
>> +{
>> +struct device   *dev = qcom->dev;
>> +struct extcon_dev   *host_edev;
>> +int ret;
>> +
>> +if (!of_property_read_bool(dev->of_node, "extcon"))
>> +return 0;
>> +
>> +qcom->edev = extcon_get_edev_by_phandle(dev, 0);
> Are the extcon phandles bound to the glue node? I don't see the
> description in the bindings doc in PATCH 1/3. And if so, would it be
> a duplicate of the child node's extcon binding? Then again, the
> alternative would be to grab it directly from the child (i.e.
> qcom->dwc3->dev.of_node) which I'm not sure is ok to do or not.
>

Yes these are bound to glue node. I missed to add it to documentation, will do
so.
I kept it separate for couple of reasons - one is to not peek too-much into 
child
node. Another reason is that doing so allows to have extcon in "peripheral"
only mode as well (not just drd mode which is the case with dwc3 core).
It allows to notify h/w when vbus is not there in device mode which IMO is
right thing to do.



-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH v2] phy: core: Allow phy_pm_runtime_xxx API calls with NULL phy

2018-04-15 Thread Manu Gautam
Hi Kishon,


On 3/20/2018 11:31 AM, Manu Gautam wrote:
> phy_init() and phy_exit() calls, and phy_power_on() and
> phy_power_off() already accept NULL as valid PHY reference
> and act as NOP. Extend same concept to phy runtime_pm APIs
> to keep drivers (e.g. dwc3) code simple while dealing with
> optional PHYs.

Wondering if you had a chance to review this.

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH v4 6/7] dt-bindings: phy-qcom-usb2: Add support to override tuning values

2018-04-15 Thread Manu Gautam
Hi,


On 4/13/2018 2:17 AM, Doug Anderson wrote:
>> Thanks for review Rob. I too agree with both the viewpoints.
>> Doug, if it is not of much concern then can I stick with current approach?
> I certainly would appreciate the #defines and believe they add to the
> readability, but if you're dead set against it and Rob says it's OK, I
> won't yell too loudly.
>
Agree to the readability part. Will add #defines as you suggested.
-thanks

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH v2 1/3] dt-bindings: usb: Update documentation for Qualcomm DWC3 driver

2018-04-16 Thread Manu Gautam
Hi Rob,


On 4/17/2018 2:08 AM, Rob Herring wrote:
> On Fri, Apr 13, 2018 at 10:21:22PM +0530, Manu Gautam wrote:
>> Existing documentation has lot of incorrect information as it
>> was originally added for a driver that no longer exists.
>>
>> Signed-off-by: Manu Gautam 
>> ---
>>  .../devicetree/bindings/usb/qcom,dwc3.txt  | 78 
>> --
>>  1 file changed, 57 insertions(+), 21 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/usb/qcom,dwc3.txt 
>> b/Documentation/devicetree/bindings/usb/qcom,dwc3.txt
>> index bc8a2fa..fdc574a 100644
>> --- a/Documentation/devicetree/bindings/usb/qcom,dwc3.txt
>> +++ b/Documentation/devicetree/bindings/usb/qcom,dwc3.txt
>> @@ -1,54 +1,90 @@
>>  Qualcomm SuperSpeed DWC3 USB SoC controller
>>  
>>  Required properties:
>> -- compatible:   should contain "qcom,dwc3"
>> +- compatible:   should contain "qcom,dwc3"
> Needs an SoC specific compatible string.

Thanks for review.
Sure. Will add that.

>
>> +- reg:  offset and length of register set for QSCRATCH 
>> wrapper
>> +- power-domains:specifies a phandle to PM domain provider node
>>  - clocks:   A list of phandle + clock-specifier pairs for the
>>  clocks listed in clock-names
>> -- clock-names:  Should contain the following:
>> +- clock-names:  Should contain the following:
>>"core"Master/Core clock, have to be >= 125 MHz for SS
>>  operation and >= 60MHz for HS operation
>> +  "mock_utmi"   Mock utmi clock needed for ITP/SOF generation in
>> +host mode. Its frequency should be 19.2MHz.
>> +  "sleep"   Sleep clock, used for wakeup when USB3 core goes
>> +into low power mode (U3).
>>  
>>  Optional clocks:
>>"iface"   System bus AXI clock.  Not present on all platforms
>> -  "sleep"   Sleep clock, used when USB3 core goes into low
>> -power mode (U3).
>> +  "cfg_noc" System Config NOC clock. Not present on all platforms
> These need to be specific as to which compatible properties have or 
> don't have these clocks.
ok

>
>> +- assigned-clocks:  should be:
>> +MOCK_UTMI_CLK
>> +MASTER_CLK
>> +- assigned-clock-rates: should be:
>> +19.2Mhz (19200) for MOCK_UTMI_CLK
>> +>=125Mhz (12500) for MASTER_CLK in SS 
>> mode
>> +>=60Mhz (6000) for MASTER_CLK in HS mode
>> +
>> +Optional properties:
>> +- resets:   list of phandle and reset specifier pairs
> How many?
I will provide exact detail for each compatible property.
>
>> +- interrupts:   specifies interrupts from controller wrapper 
>> used
>> +to wakeup from low power/susepnd state. Must contain
>> +one or more entry for interrupt-names property
>> +- interrupt-names:  Must include the following entries:
>> +- "hs_phy_irq": The interrupt that is asserted when a
>> +   wakeup event is received on USB2 bus
>> +- "ss_phy_irq": The interrupt that is asserted when a
>> +   wakeup event is received on USB3 bus
>> +- "dm_hs_phy_irq" and "dp_hs_phy_irq": Separate
>> +   interrupts for any wakeup event on DM and DP lines
> Sounds like the irqs are actually part of the PHYs? If so, then that's 
> where they should be in the DT.
No. These are actually part of controller wrapper called - qscratch which
has connectivity to phy outputs signals. Also, these are abstracted from PHY
and are present irrespective of type of phy present. I will add soc specific
info also in comments specifying which interrupts are not present on particular
soc/compatible.

>
>> +- qcom,select-utmi-as-pipe-clk: if present, disable USB3 pipe_clk 
>> requirement.
>> +Used when dwc3 operates without SSPHY and only
>> +HS/FS/LS modes are supported.
>>  
>>  Required child node:
>>  A child node must exist to represent the core DWC3 IP block. The name of
>>  the node is not important. The content of the node is defined in dwc3.txt.
>> 

[PATCH v4 2/3] usb: dwc3: Add Qualcomm DWC3 glue driver

2018-05-09 Thread Manu Gautam
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.
 - pwr_events_irq_stat support to check if USB2 PHY is in L2 state
   before glue driver proceeds with suspend.
 - Support for wakeup interrupts lines that are asserted whenever
   there is any wakeup event on USB3 or USB2 bus.
 - Support to replace pip3 clock going to DWC3 with utmi clock
   for hardware configuration where SSPHY is not used with DWC3.

Signed-off-by: Manu Gautam 
---
 drivers/usb/dwc3/Kconfig  |  12 +
 drivers/usb/dwc3/Makefile |   1 +
 drivers/usb/dwc3/dwc3-of-simple.c |   1 -
 drivers/usb/dwc3/dwc3-qcom.c  | 620 ++
 4 files changed, 633 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..451012e 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -106,4 +106,16 @@ config USB_DWC3_ST
  inside (i.e. STiH407).
  Say 'Y' or 'M' if you have one such device.
 
+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.
+ This driver also handles Qscratch wrapper which is needed
+ for peripheral mode support.
+ Say 'Y' or 'M' if you have one such device.
+
 endif
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
index 025bc68..5c07d8f 100644
--- a/drivers/usb/dwc3/Makefile
+++ b/drivers/usb/dwc3/Makefile
@@ -48,3 +48,4 @@ obj-$(CONFIG_USB_DWC3_PCI)+= dwc3-pci.o
 obj-$(CONFIG_USB_DWC3_KEYSTONE)+= dwc3-keystone.o
 obj-$(CONFIG_USB_DWC3_OF_SIMPLE)   += dwc3-of-simple.o
 obj-$(CONFIG_USB_DWC3_ST)  += dwc3-st.o
+obj-$(CONFIG_USB_DWC3_QCOM)+= 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 device *dev)
 };
 
 static const struct of_device_id of_dwc3_simple_match[] = {
-   { .compatible = "qcom,dwc3" },
{ .compatible = "rockchip,rk3399-dwc3" },
{ .compatible = "xlnx,zynqmp-dwc3" },
{ .compatible = "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 000..8abb6f3
--- /dev/null
+++ b/drivers/usb/dwc3/dwc3-qcom.c
@@ -0,0 +1,620 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * Inspired by dwc3-of-simple.c
+ */
+#define DEBUG
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "core.h"
+
+/* USB QSCRATCH Hardware registers */
+#define QSCRATCH_HS_PHY_CTRL   0x10
+#define UTMI_OTG_VBUS_VALIDBIT(20)
+#define SW_SESSVLD_SEL BIT(28)
+
+#define QSCRATCH_SS_PHY_CTRL   0x30
+#define LANE0_PWR_PRESENT  BIT(24)
+
+#define QSCRATCH_GENERAL_CFG   0x08
+#define PIPE_UTMI_CLK_SEL  BIT(0)
+#define PIPE3_PHYSTATUS_SW BIT(3)
+#define PIPE_UTMI_CLK_DIS  BIT(8)
+
+#define PWR_EVNT_IRQ_STAT_REG  0x58
+#define PWR_EVNT_LPM_IN_L2_MASKBIT(4)
+#define PWR_EVNT_LPM_OUT_L2_MASK   BIT(5)
+
+struct dwc3_qcom {
+   struct device   *dev;
+   void __iomem*qscratch_base;
+   struct platform_device  *dwc3;
+   struct clk  **clks;
+   int num_clocks;
+   struct reset_control*resets;
+
+   int hs_phy_irq;
+   int dp_hs_phy_irq;
+   int dm_hs_phy_irq;
+   int ss_phy_irq;
+
+   struct extcon_dev   *edev;
+   struct extcon_dev   *host_edev;
+   struct notifier_block   vbus_nb;
+   struct notifier_block   host_nb;
+
+   enum usb_dr_modemode;
+   boolis_suspended;
+   boolpm_suspended;
+};
+
+static inli

[PATCH v4 3/3] usb: dwc3: core: Suspend PHYs on runtime suspend in host mode

2018-05-09 Thread Manu Gautam
Some PHY drivers (e.g. for Qualcomm QUSB2 and QMP PHYs) support
runtime PM to reduce PHY power consumption during bus_suspend.
Add changes to let core auto-suspend PHYs on host bus-suspend
using GUSB2PHYCFG register if needed for a platform. Also perform
PHYs runtime suspend/resume and let platform glue drivers e.g.
dwc3-qcom handle remote wakeup during bus suspend by waking up
devices on receiving wakeup event from PHY.

Signed-off-by: Manu Gautam 
---
 drivers/usb/dwc3/core.c | 36 +---
 1 file changed, 33 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index a15648d..449a098 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -1394,6 +1394,7 @@ static int dwc3_remove(struct platform_device *pdev)
 static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
 {
unsigned long   flags;
+   u32 reg;
 
switch (dwc->current_dr_role) {
case DWC3_GCTL_PRTCAP_DEVICE:
@@ -1403,9 +1404,25 @@ static int dwc3_suspend_common(struct dwc3 *dwc, 
pm_message_t msg)
dwc3_core_exit(dwc);
break;
case DWC3_GCTL_PRTCAP_HOST:
-   /* do nothing during host runtime_suspend */
-   if (!PMSG_IS_AUTO(msg))
+   if (!PMSG_IS_AUTO(msg)) {
dwc3_core_exit(dwc);
+   break;
+   }
+
+   /* Let controller to suspend HSPHY before PHY driver suspends */
+   if (dwc->dis_u2_susphy_quirk ||
+   dwc->dis_enblslpm_quirk) {
+   reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+   reg |=  DWC3_GUSB2PHYCFG_ENBLSLPM |
+   DWC3_GUSB2PHYCFG_SUSPHY;
+   dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+
+   /* Give some time for USB2 PHY to suspend */
+   usleep_range(5000, 6000);
+   }
+
+   phy_pm_runtime_put_sync(dwc->usb2_generic_phy);
+   phy_pm_runtime_put_sync(dwc->usb3_generic_phy);
break;
case DWC3_GCTL_PRTCAP_OTG:
/* do nothing during runtime_suspend */
@@ -1433,6 +1450,7 @@ static int dwc3_resume_common(struct dwc3 *dwc, 
pm_message_t msg)
 {
unsigned long   flags;
int ret;
+   u32 reg;
 
switch (dwc->current_dr_role) {
case DWC3_GCTL_PRTCAP_DEVICE:
@@ -1446,13 +1464,25 @@ static int dwc3_resume_common(struct dwc3 *dwc, 
pm_message_t msg)
spin_unlock_irqrestore(&dwc->lock, flags);
break;
case DWC3_GCTL_PRTCAP_HOST:
-   /* nothing to do on host runtime_resume */
if (!PMSG_IS_AUTO(msg)) {
ret = dwc3_core_init(dwc);
if (ret)
return ret;
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
+   break;
}
+   /* Restore GUSB2PHYCFG bits that were modified in suspend */
+   reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+   if (dwc->dis_u2_susphy_quirk)
+   reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
+
+   if (dwc->dis_enblslpm_quirk)
+   reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
+
+   dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+
+   phy_pm_runtime_get_sync(dwc->usb2_generic_phy);
+   phy_pm_runtime_get_sync(dwc->usb3_generic_phy);
break;
case DWC3_GCTL_PRTCAP_OTG:
/* nothing to do on runtime_resume */
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v4 0/3] usb: dwc3: support for Qualcomm DWC3 glue

2018-05-09 Thread Manu Gautam
Add separate dwc3-qcom glue driver for Qualcomm SOCs having dwc3 core.
It is needed to support peripheral mode.
Patches also add support to invoke PHY runtime PM functions on host
mode bus-suspend.

Changes since v3:
 - Added SOC specific compatibles in driver.

Changes since v2:
 - Addressed Rob's comments for DT binding documentation.

Changes since v1:
 - Move dwc3 core register accesses from glue driver to dwc3 core as
   per review comment from Felipe.
 - Addressed other review comments from Felipe and Rob.
 - Some other minor code changes related to redability.
 - Add reset_control assert in driver probe to ensure core registers
   are reset to POR value in case of any initalization by boot code. 

Manu Gautam (3):
  dt-bindings: usb: Update documentation for Qualcomm DWC3 driver
  usb: dwc3: Add Qualcomm DWC3 glue driver
  usb: dwc3: core: Suspend PHYs on runtime suspend in host mode

 .../devicetree/bindings/usb/qcom,dwc3.txt  |  85 ++-
 drivers/usb/dwc3/Kconfig   |  12 +
 drivers/usb/dwc3/Makefile  |   1 +
 drivers/usb/dwc3/core.c|  36 +-
 drivers/usb/dwc3/dwc3-of-simple.c  |   1 -
 drivers/usb/dwc3/dwc3-qcom.c   | 620 +
 6 files changed, 729 insertions(+), 26 deletions(-)
 create mode 100644 drivers/usb/dwc3/dwc3-qcom.c

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v4 1/3] dt-bindings: usb: Update documentation for Qualcomm DWC3 driver

2018-05-09 Thread Manu Gautam
Existing documentation has lot of incorrect information as it
was originally added for a driver that no longer exists.

Signed-off-by: Manu Gautam 
Reviewed-by: Rob Herring 
---
 .../devicetree/bindings/usb/qcom,dwc3.txt  | 85 --
 1 file changed, 63 insertions(+), 22 deletions(-)

diff --git a/Documentation/devicetree/bindings/usb/qcom,dwc3.txt 
b/Documentation/devicetree/bindings/usb/qcom,dwc3.txt
index bc8a2fa..95afdcf 100644
--- a/Documentation/devicetree/bindings/usb/qcom,dwc3.txt
+++ b/Documentation/devicetree/bindings/usb/qcom,dwc3.txt
@@ -1,54 +1,95 @@
 Qualcomm SuperSpeed DWC3 USB SoC controller
 
 Required properties:
-- compatible:  should contain "qcom,dwc3"
+- compatible:  Compatible list, contains
+   "qcom,dwc3"
+   "qcom,msm8996-dwc3" for msm8996 SOC.
+   "qcom,sdm845-dwc3" for sdm845 SOC.
+- reg: Offset and length of register set for QSCRATCH wrapper
+- power-domains:   specifies a phandle to PM domain provider node
 - clocks:  A list of phandle + clock-specifier pairs for the
clocks listed in clock-names
-- clock-names: Should contain the following:
+- clock-names: Should contain the following:
   "core"   Master/Core clock, have to be >= 125 MHz for SS
operation and >= 60MHz for HS operation
+  "mock_utmi"  Mock utmi clock needed for ITP/SOF generation in
+   host mode. Its frequency should be 19.2MHz.
+  "sleep"  Sleep clock, used for wakeup when USB3 core goes
+   into low power mode (U3).
 
 Optional clocks:
-  "iface"  System bus AXI clock.  Not present on all platforms
-  "sleep"  Sleep clock, used when USB3 core goes into low
-   power mode (U3).
+  "iface"  System bus AXI clock.
+   Not present on "qcom,msm8996-dwc3" compatible.
+  "cfg_noc"System Config NOC clock.
+   Not present on "qcom,msm8996-dwc3" compatible.
+- assigned-clocks: Should be:
+   MOCK_UTMI_CLK
+   MASTER_CLK
+- assigned-clock-rates: Should be:
+19.2Mhz (19200) for MOCK_UTMI_CLK
+>=125Mhz (12500) for MASTER_CLK in SS mode
+>=60Mhz (6000) for MASTER_CLK in HS mode
+
+Optional properties:
+- resets:  Phandle to reset control that resets core and wrapper.
+- interrupts:  specifies interrupts from controller wrapper used
+   to wakeup from low power/susepnd state. Must contain
+   one or more entry for interrupt-names property
+- interrupt-names: Must include the following entries:
+   - "hs_phy_irq": The interrupt that is asserted when a
+  wakeup event is received on USB2 bus
+   - "ss_phy_irq": The interrupt that is asserted when a
+  wakeup event is received on USB3 bus
+   - "dm_hs_phy_irq" and "dp_hs_phy_irq": Separate
+  interrupts for any wakeup event on DM and DP lines
+- qcom,select-utmi-as-pipe-clk: if present, disable USB3 pipe_clk requirement.
+   Used when dwc3 operates without SSPHY and only
+   HS/FS/LS modes are supported.
 
 Required child node:
 A child node must exist to represent the core DWC3 IP block. The name of
 the node is not important. The content of the node is defined in dwc3.txt.
 
 Phy documentation is provided in the following places:
-Documentation/devicetree/bindings/phy/qcom-dwc3-usb-phy.txt
+Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt   - USB3 QMP PHY
+Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt - USB2 QUSB2 PHY
 
 Example device nodes:
 
hs_phy: phy@100f8800 {
-   compatible = "qcom,dwc3-hs-usb-phy";
-   reg = <0x100f8800 0x30>;
-   clocks = <&gcc USB30_0_UTMI_CLK>;
-   clock-names = "ref";
-   #phy-cells = <0>;
-
+   compatible = "qcom,qusb2-v2-phy";
+   ...
};
 
ss_phy: phy@100f8830 {
-   compatible = "qcom,dwc3-ss-usb-phy";
-   reg = <0x100f8830 0x30>;
-   clocks = <&gcc USB30_0_MASTER_CLK>;
-   clock-names = "ref";

Re: [PATCH v1 2/2] usb: dwc3: Add Qualcomm DWC3 glue driver

2018-03-15 Thread Manu Gautam
Hi,


On 3/14/2018 2:20 PM, Felipe Balbi wrote:
> Hi,
>
> Manu Gautam  writes:
>
[snip]
>>>>  - 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.
>> Yes, with this we can use dwc3 without using SSPHY. Please point me to
>> those patches. There are only bunch of register writes in glue wrapper to
>> achieve the same.
> https://www.spinics.net/lists/linux-usb/msg160868.html

I looked at the patchset and thinking that adding mux for this may
not be of much help here. Qscratch is part of dwc3 wrapper
and uses same clock domain for its registers. Hence, I can't
have a separate mux driver for same. Will have to register
mux controller from this driver for these and use only in this driver
as I dont expect any other client for same. So, can I proceed with
existing logic?

>
>>>> +static int dwc3_qcom_suspend(struct dwc3_qcom *qcom)
>>>> +{
>>>> +  struct dwc3 *dwc = platform_get_drvdata(qcom->dwc3);
>>> nope! Glue shouldn't touch dwc3 at all.
>> Other than PHY handles, need this to fail runtime suspend if dwc3 hasn't
>> probed yet.
> Will that even happen? You should pm_runtime_forbid() by default,
> anyway and expect it to be enabled via sysfs later, no?

It happens if I enable runtime_pm from probe which is the case right now.
I will disable it from probe as you suggested.
In any case dwc3 uses pm_runtime_forbid and expects it to be enabled from sysfs,
so I dont get any benefit of enabling it from glue driver probe.

Other than this, I need to access 'dwc->xhci' to resume root hub on remote 
wakeup.
That I missed to mention earlier.

>
>>>> +  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.
>> Recommended sequence from h/w programming guide is that:
>> 1. PHY autosuspend must be left disabled - 
>> snps,dis_u2_susphy_quirk/dis_enblslpm_quirk
>> 2. During runtime-suspend (say on xhci bus_suspend) , PHY should be suspended
>>     using GUSB2PHYCFG register
> this is something that dwc3 core can do on its own suspend implementation.
>
>> 3. Wait until pwr_event_irq_stat in qscratch reflects PHY transition to L2.
> this is interesting part. Is this register accessible by the PHY driver?
> Seems like that would be the best place to stuff this...

This register is in controller wrapper which PHY driver can't access.
Also clock domain is different.

>
>> 3. USB2 PHY driver can suspend - enable wakeup events and turns off clocks 
>> etc.
> ... together with this.
>
>> 4. dwc3 glue driver can suspend.
>>
>> Since, pwr_event_irq stat can't be checked in core driver, I added this 
>> handling
>> in glue driver. Alternative approach I can think of is to let dwc3 core 
>> suspend
>> PHY using GUSBPHYCFG register on suspend,  add some delay before
>> suspending PHY. Glue driver can check for pwr_event_irq stat and throw a
>> warning if PHY not in L2.
> almost :-) core_suspend fiddles with GUSB2PHYCFG for suspend and calls
> phy_suspend() (or whatever the function is called heh), that will go to
> your phy driver's suspend callback, which checks pwr_event_irq_stat and
> then pm_runtime_put() to schedule ->runtime_suspend() so that can enable
> wakeups and switch off clocks.

Since phy driver can not access pwr_event_irq_stat, should I just use some delay
and assume PHY gets suspended?

>
>>>> +  irq = 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?
>> These wakeup_irqs should be enabled only during suspend. With this flag I
>> don't need to disable irq immediately after requesting it.
> oh, okay. You may want to add a comment here :-)
Sure.

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH] phy: core: Allow phy_pm_runtime_xxx API calls with NULL phy

2018-03-16 Thread Manu Gautam
phy_init() and phy_exit() calls, and phy_power_on() and
phy_power_off() already accept NULL as valid PHY refernece
and act as NOP. Extend same concept to phy runtime_pm APIs
to keep drivers (e.g. dwc3) code simple while dealing with
optional PHYs.

Signed-off-by: Manu Gautam 
---
 drivers/phy/phy-core.c | 18 ++
 1 file changed, 18 insertions(+)

diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
index 09ac8af..48b9615 100644
--- a/drivers/phy/phy-core.c
+++ b/drivers/phy/phy-core.c
@@ -153,6 +153,9 @@ int phy_pm_runtime_get(struct phy *phy)
 {
int ret;
 
+   if (!phy)
+   return 0;
+
if (!pm_runtime_enabled(&phy->dev))
return -ENOTSUPP;
 
@@ -168,6 +171,9 @@ int phy_pm_runtime_get_sync(struct phy *phy)
 {
int ret;
 
+   if (!phy)
+   return 0;
+
if (!pm_runtime_enabled(&phy->dev))
return -ENOTSUPP;
 
@@ -181,6 +187,9 @@ int phy_pm_runtime_get_sync(struct phy *phy)
 
 int phy_pm_runtime_put(struct phy *phy)
 {
+   if (!phy)
+   return 0;
+
if (!pm_runtime_enabled(&phy->dev))
return -ENOTSUPP;
 
@@ -190,6 +199,9 @@ int phy_pm_runtime_put(struct phy *phy)
 
 int phy_pm_runtime_put_sync(struct phy *phy)
 {
+   if (!phy)
+   return 0;
+
if (!pm_runtime_enabled(&phy->dev))
return -ENOTSUPP;
 
@@ -199,6 +211,9 @@ int phy_pm_runtime_put_sync(struct phy *phy)
 
 void phy_pm_runtime_allow(struct phy *phy)
 {
+   if (!phy)
+   return 0;
+
if (!pm_runtime_enabled(&phy->dev))
return;
 
@@ -208,6 +223,9 @@ void phy_pm_runtime_allow(struct phy *phy)
 
 void phy_pm_runtime_forbid(struct phy *phy)
 {
+   if (!phy)
+   return 0;
+
if (!pm_runtime_enabled(&phy->dev))
return;
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH 2/6] phy: qcom-qusb2: Fix crash if nvmem cell not specified

2018-03-16 Thread Manu Gautam
Driver currently crashes due to NULL pointer deference
while updating PHY tune register if nvmem cell is NULL.
Since, fused value for Tune1/2 register is optional,
we'd rather bail out.

Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qusb2.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c 
b/drivers/phy/qualcomm/phy-qcom-qusb2.c
index 94afeac..40fdef8 100644
--- a/drivers/phy/qualcomm/phy-qcom-qusb2.c
+++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c
@@ -315,6 +315,10 @@ static void qusb2_phy_set_tune2_param(struct qusb2_phy 
*qphy)
const struct qusb2_phy_cfg *cfg = qphy->cfg;
u8 *val;
 
+   /* efuse register is optional */
+   if (!qphy->cell)
+   return;
+
/*
 * Read efuse register having TUNE2/1 parameter's high nibble.
 * If efuse register shows value as 0x0, or if we fail to find
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH 1/6] phy: qcom-qmp: Enable pipe_clk before checking USB3 PHY_STATUS

2018-03-16 Thread Manu Gautam
QMP PHY for USB mode requires pipe_clk for calibration and PLL lock
to take place. This lock is output from PHY to GCC clock_ctl and then
fed back to QMP PHY and is output from PHY only after PHY is reset
and initialized, hence it can't be enabled too early in initialization
sequence.

Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qmp.c | 18 ++
 1 file changed, 18 insertions(+)

diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c 
b/drivers/phy/qualcomm/phy-qcom-qmp.c
index 6470c5d..73aa282 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.c
@@ -797,8 +797,13 @@ static int qcom_qmp_phy_poweron(struct phy *phy)
 {
struct qmp_phy *qphy = phy_get_drvdata(phy);
struct qcom_qmp *qmp = qphy->qmp;
+   const struct qmp_phy_cfg *cfg = qmp->cfg;
int ret;
 
+   /* Not needed for USB3 PHY as pipe_clk is enabled from phy_init */
+   if (cfg->type == PHY_TYPE_USB3)
+   return 0;
+
ret = clk_prepare_enable(qphy->pipe_clk);
if (ret)
dev_err(qmp->dev, "pipe_clk enable failed, err=%d\n", ret);
@@ -1008,6 +1013,19 @@ static int qcom_qmp_phy_init(struct phy *phy)
status = pcs + cfg->regs[QPHY_PCS_READY_STATUS];
mask = cfg->mask_pcs_ready;
 
+   /* USB3 PHY requires pipe_clk for PLL lock and calibration */
+   if (cfg->type == PHY_TYPE_USB3) {
+   ret = clk_prepare_enable(qphy->pipe_clk);
+   if (ret)
+   dev_err(qmp->dev, "pipe_clk enable err=%d\n", ret);
+   /*
+* Ignore this error as pipe_clk might take some time to get
+* enabled. In any case following check for PHY PLL lock would
+* timeout below if there is a fatal error and clock is not fed
+* to PHY
+*/
+   }
+
ret = readl_poll_timeout(status, val, !(val & mask), 1,
 PHY_INIT_COMPLETE_TIMEOUT);
if (ret) {
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH 4/6] phy: qcom-qmp: Add QMP V3 USB3 UNI PHY support for sdm845

2018-03-16 Thread Manu Gautam
QMP V3 UNI PHY is a single lane USB3 PHY without support
for DisplayPort (DP).
Main difference from DP combo QMPv3 PHY is that UNI PHY
doesn't have dual RX/TX lanes and no separate DP_COM
block for configuration related to type-c or DP.
While at it, fix has_pwrdn_delay attribute for USB-DP
PHY configuration.

Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qmp.c | 148 
 drivers/phy/qualcomm/phy-qcom-qmp.h |   5 ++
 2 files changed, 153 insertions(+)

diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c 
b/drivers/phy/qualcomm/phy-qcom-qmp.c
index 73aa282..689951d 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.c
@@ -490,6 +490,118 @@ enum qphy_reg_layout {
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_RUN_TIME, 0x13),
 };
 
+static const struct qmp_phy_init_tbl qmp_v3_usb3_uniphy_serdes_tbl[] = {
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_IVCO, 0x07),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_EN_SEL, 0x14),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x04),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x30),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYS_CLK_CTRL, 0x02),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_RESETSM_CNTRL2, 0x08),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_CONFIG, 0x06),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_SVS_MODE_CLK_SEL, 0x01),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_HSCLK_SEL, 0x80),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_DEC_START_MODE0, 0x82),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START1_MODE0, 0xab),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START2_MODE0, 0xea),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START3_MODE0, 0x02),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_CP_CTRL_MODE0, 0x06),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_RCTRL_MODE0, 0x16),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_CCTRL_MODE0, 0x36),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE0, 0x00),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE0, 0x3f),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE2_MODE0, 0x01),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE1_MODE0, 0xc9),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORECLK_DIV_MODE0, 0x0a),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP3_MODE0, 0x00),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP2_MODE0, 0x34),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP1_MODE0, 0x15),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_EN, 0x04),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORE_CLK_EN, 0x00),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_CFG, 0x00),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_MAP, 0x00),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_BUF_ENABLE, 0x0a),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_EN_CENTER, 0x01),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER1, 0x31),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER2, 0x01),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER1, 0x00),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER2, 0x00),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE1, 0x85),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE2, 0x07),
+};
+
+static const struct qmp_phy_init_tbl qmp_v3_usb3_uniphy_tx_tbl[] = {
+   QMP_PHY_INIT_CFG(QSERDES_V3_TX_HIGHZ_DRVR_EN, 0x10),
+   QMP_PHY_INIT_CFG(QSERDES_V3_TX_RCV_DETECT_LVL_2, 0x12),
+   QMP_PHY_INIT_CFG(QSERDES_V3_TX_LANE_MODE_1, 0xc6),
+   QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_RX, 0x06),
+   QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX, 0x06),
+};
+
+static const struct qmp_phy_init_tbl qmp_v3_usb3_uniphy_rx_tbl[] = {
+   QMP_PHY_INIT_CFG(QSERDES_V3_RX_VGA_CAL_CNTRL2, 0x0c),
+   QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x50),
+   QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b),
+   QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0e),
+   QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4e),
+   QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4, 0x18),
+   QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x77),
+   QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80),
+   QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x03),
+   QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x1c),
+   QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x75),
+};
+
+static const struct qmp_phy_init_tbl qmp_v3_usb3_uniphy_pcs_tbl[] = {
+   /* FLL settings */
+   QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL2, 0x83),
+   QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_L, 0x09),
+   QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_H_TOL, 0xa2),
+   QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_MAN_CODE, 0x40),
+   QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL1, 0x02),
+
+   /* Lock Det settings */
+   QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG1, 0xd1),
+   QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG2, 0x1f),
+   QMP_PHY_INI

[PATCH 3/6] dt-bindings: phy-qcom-qmp: Update bindings for sdm845

2018-03-16 Thread Manu Gautam
Update compatible strings for USB3 PHYs on SDM845.
One is QMPv3 DisplayPort-USB combo PHY and other one
is USB UNI PHY which is single lane USB3 PHY without
DP capability.

Signed-off-by: Manu Gautam 
---
 Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt 
b/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt
index dcf1b8f..cef8765 100644
--- a/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt
+++ b/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt
@@ -9,7 +9,9 @@ Required properties:
   "qcom,ipq8074-qmp-pcie-phy" for PCIe phy on IPQ8074
   "qcom,msm8996-qmp-pcie-phy" for 14nm PCIe phy on msm8996,
   "qcom,msm8996-qmp-usb3-phy" for 14nm USB3 phy on msm8996,
-  "qcom,qmp-v3-usb3-phy" for USB3 QMP V3 phy.
+  "qcom,qmp-v3-usb3-phy" for USB3 QMP V3 phy,
+  "qcom,sdm845-qmp-usb3-phy" for USB3 QMP V3 phy on sdm845,
+  "qcom,sdm845-qmp-usb3-uni-phy" for USB3 QMP V3 UNI phy on sdm845.
 
  - reg: offset and length of register set for PHY's common serdes block.
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH 5/6] dt-bindings: phy-qcom-usb2: Update bindings for sdm845

2018-03-16 Thread Manu Gautam
Update compatible strings for USB2 PHYs on sdm845.
There are two QUSB2 PHYs present on sdm845. Few PHY registers
programming is different for these PHYs related to electrical
parameters, otherwise both are same.

Signed-off-by: Manu Gautam 
---
 Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt 
b/Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt
index 42c9742..20deaeb 100644
--- a/Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt
+++ b/Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt
@@ -6,7 +6,9 @@ QUSB2 controller supports LS/FS/HS usb connectivity on Qualcomm 
chipsets.
 Required properties:
  - compatible: compatible list, contains
   "qcom,msm8996-qusb2-phy" for 14nm PHY on msm8996,
-  "qcom,qusb2-v2-phy" for QUSB2 V2 PHY.
+  "qcom,qusb2-v2-phy" for QUSB2 V2 PHY,
+  "qcom,sdm845-1-qusb2-phy" for primary PHY on sdm845,
+  "qcom,sdm845-2-qusb2-phy" for secondary PHY on sdm845.
 
  - reg: offset and length of the PHY register set.
  - #phy-cells: must be 0.
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH 6/6] phy: qcom-qusb2: Add QUSB2 PHYs support for sdm845

2018-03-16 Thread Manu Gautam
There are two QUSB2 PHYs present on sdm845. Update PHY
registers programming for both the PHYs related to
electrical parameters to improve eye diagram.

Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qusb2.c | 39 +++
 1 file changed, 39 insertions(+)

diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c 
b/drivers/phy/qualcomm/phy-qcom-qusb2.c
index 40fdef8..1a608a9 100644
--- a/drivers/phy/qualcomm/phy-qcom-qusb2.c
+++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c
@@ -174,6 +174,27 @@ enum qusb2phy_reg_layout {
QUSB2_PHY_INIT_CFG(QUSB2PHY_CHG_CTRL2, 0x0),
 };
 
+static const struct qusb2_phy_init_tbl sdm845_init_tbl_1[] = {
+   QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_ANALOG_CONTROLS_TWO, 0x03),
+   QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_CLOCK_INVERTERS, 0x7c),
+   QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_CMODE, 0x80),
+   QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_LOCK_DELAY, 0x0a),
+   QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_DIGITAL_TIMERS_TWO, 0x19),
+   QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_BIAS_CONTROL_1, 0x40),
+   QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_BIAS_CONTROL_2, 0x20),
+   QUSB2_PHY_INIT_CFG(QUSB2PHY_PWR_CTRL2, 0x21),
+   QUSB2_PHY_INIT_CFG(QUSB2PHY_IMP_CTRL1, 0x8),
+   QUSB2_PHY_INIT_CFG(QUSB2PHY_IMP_CTRL2, 0x58),
+
+   QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE1, 0x45),
+   QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE2, 0x29),
+   QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE3, 0xca),
+   QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE4, 0x04),
+   QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE5, 0x03),
+
+   QUSB2_PHY_INIT_CFG(QUSB2PHY_CHG_CTRL2, 0x0),
+};
+
 struct qusb2_phy_cfg {
const struct qusb2_phy_init_tbl *tbl;
/* number of entries in the table */
@@ -220,6 +241,18 @@ struct qusb2_phy_cfg {
.autoresume_en= BIT(0),
 };
 
+static const struct qusb2_phy_cfg sdm845_phy_cfg_1 = {
+   .tbl= sdm845_init_tbl_1,
+   .tbl_num= ARRAY_SIZE(sdm845_init_tbl_1),
+   .regs   = qusb2_v2_regs_layout,
+
+   .disable_ctrl   = (PWR_CTRL1_VREF_SUPPLY_TRIM | PWR_CTRL1_CLAMP_N_EN |
+  POWER_DOWN),
+   .mask_core_ready = CORE_READY_STATUS,
+   .has_pll_override = true,
+   .autoresume_en= BIT(0),
+};
+
 static const char * const qusb2_phy_vreg_names[] = {
"vdda-pll", "vdda-phy-dpdm",
 };
@@ -649,6 +682,12 @@ static int qusb2_phy_exit(struct phy *phy)
}, {
.compatible = "qcom,qusb2-v2-phy",
.data   = &qusb2_v2_phy_cfg,
+   }, {
+   .compatible = "qcom,sdm845-1-qusb2-phy",
+   .data   = &sdm845_phy_cfg_1,
+   }, {
+   .compatible = "qcom,sdm845-2-qusb2-phy",
+   .data   = &qusb2_v2_phy_cfg,
},
{ },
 };
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH v3 2/3] usb: dwc3: Add Qualcomm DWC3 glue driver

2018-05-07 Thread Manu Gautam


On 5/5/2018 12:18 AM, Manu Gautam wrote:
> 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.
>  - pwr_events_irq_stat support to check if USB2 PHY is in L2 state
>before glue driver proceeds with suspend.
>  - Support for wakeup interrupts lines that are asserted whenever
>there is any wakeup event on USB3 or USB2 bus.
>  - Support to replace pip3 clock going to DWC3 with utmi clock
>for hardware configuration where SSPHY is not used with DWC3.
>
> Signed-off-by: Manu Gautam 
[snip]
> +static const struct of_device_id dwc3_qcom_of_match[] = {
> + { .compatible = "qcom,dwc3" },

I should also add SOC specific compatibles.
Will do that in next patch.


-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH v3 3/3] clk: qcom: Add Global Clock controller (GCC) driver for SDM845

2018-04-18 Thread Manu Gautam
Hi Amit,


On 4/18/2018 6:33 PM, Amit Nischal wrote:
>>> +   /* Disable the GPLL0 active input to MMSS and GPU via MISC 
>>> registers */
>>> +   regmap_update_bits(regmap, 0x09ffc, 0x3, 0x3);
>>> +   regmap_update_bits(regmap, 0x71028, 0x3, 0x3);
>>
>> I think we'll have to throw in the pipe clk branch stuff in here too?
>> And then drop the pipe clks from the driver?
>
> All the USB pipe clocks would be taken care. The PCIE pipe branch
> clocks would have to be explicitly disabled so as to retain the
> memory logic. Otherwise, it would lead to memory corruption in case
> the external source is directly disabled without disabling the branch clock. 

PHY driver is same for both USB and PCIE and both PHYs use pipe_clk.
If there is indeed some limitation and pipe_clk cant be left enabled
always then I will suggest to not change pipe_clk handling for USB as well.

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH v1 05/10] bus: mhi: core: Disable IRQs when powering down

2020-10-10 Thread Manu Gautam
Hi

On 9/19/2020 7:32 AM, Bhaumik Bhatt wrote:
> While powering down, the device may or may not acknowledge the MHI
> RESET issued by host for graceful shutdown scenario which can lead
> to a rogue device sending an interrupt after the clean-up has been
> done. This can result in a tasklet being scheduled after it has
> been killed and access already freed memory causing a NULL pointer
> exception. Avoid this corner case by disabling the interrupts as a
> part of host clean up.
>
> Signed-off-by: Bhaumik Bhatt 
> ---
>  drivers/bus/mhi/core/pm.c | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/drivers/bus/mhi/core/pm.c b/drivers/bus/mhi/core/pm.c
> index 1862960..3462d82 100644
> --- a/drivers/bus/mhi/core/pm.c
> +++ b/drivers/bus/mhi/core/pm.c
> @@ -517,6 +517,7 @@ static void mhi_pm_disable_transition(struct 
> mhi_controller *mhi_cntrl,
>   for (i = 0; i < mhi_cntrl->total_ev_rings; i++, mhi_event++) {
>   if (mhi_event->offload_ev)
>   continue;
> + disable_irq(mhi_cntrl->irq[mhi_event->irq]);
>   tasklet_kill(&mhi_event->task);
>   }
>  

What about sys_err handling? IRQ may be left disabled?


-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH v1 06/10] bus: mhi: core: Improve shutdown handling after link down detection

2020-10-10 Thread Manu Gautam


On 9/19/2020 7:32 AM, Bhaumik Bhatt wrote:
> If MHI were to attempt a device shutdown following an assumption
> that the device is inaccessible, the host currently moves to a state
> where device register accesses are allowed when they should not be.
> This would end up allowing accesses to the device register space when
> the link is inaccessible and can result in bus errors observed on the
> host. Improve shutdown handling to prevent these outcomes and do not
> move the MHI PM state to a register accessible state after device is

Which state are you referring to when you say 'register accessible state'?
Would it be possible to provide more details on current handling here?


> assumed to be inaccessible.
>
> Signed-off-by: Bhaumik Bhatt 
> ---
>  drivers/bus/mhi/core/init.c |  1 +
>  drivers/bus/mhi/core/internal.h |  1 +
>  drivers/bus/mhi/core/pm.c   | 18 +-
>  3 files changed, 15 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/bus/mhi/core/init.c b/drivers/bus/mhi/core/init.c
> index 9ae4c19..fa33dde 100644
> --- a/drivers/bus/mhi/core/init.c
> +++ b/drivers/bus/mhi/core/init.c
> @@ -37,6 +37,7 @@ const char * const 
> dev_state_tran_str[DEV_ST_TRANSITION_MAX] = {
>   [DEV_ST_TRANSITION_MISSION_MODE] = "MISSION_MODE",
>   [DEV_ST_TRANSITION_SYS_ERR] = "SYS_ERR",
>   [DEV_ST_TRANSITION_DISABLE] = "DISABLE",
> + [DEV_ST_TRANSITION_FATAL] = "FATAL SHUTDOWN",
>  };
>  
>  const char * const mhi_state_str[MHI_STATE_MAX] = {
> diff --git a/drivers/bus/mhi/core/internal.h b/drivers/bus/mhi/core/internal.h
> index 7989269..f3b9e5a 100644
> --- a/drivers/bus/mhi/core/internal.h
> +++ b/drivers/bus/mhi/core/internal.h
> @@ -388,6 +388,7 @@ enum dev_st_transition {
>   DEV_ST_TRANSITION_MISSION_MODE,
>   DEV_ST_TRANSITION_SYS_ERR,
>   DEV_ST_TRANSITION_DISABLE,
> + DEV_ST_TRANSITION_FATAL,
>   DEV_ST_TRANSITION_MAX,
>  };
>  
> diff --git a/drivers/bus/mhi/core/pm.c b/drivers/bus/mhi/core/pm.c
> index 3462d82..bce1f62 100644
> --- a/drivers/bus/mhi/core/pm.c
> +++ b/drivers/bus/mhi/core/pm.c
> @@ -37,9 +37,10 @@
>   * M0 -> FW_DL_ERR
>   * M0 -> M3_ENTER -> M3 -> M3_EXIT --> M0
>   * L1: SYS_ERR_DETECT -> SYS_ERR_PROCESS --> POR
> - * L2: SHUTDOWN_PROCESS -> DISABLE
> + * L2: SHUTDOWN_PROCESS -> LD_ERR_FATAL_DETECT
> + * SHUTDOWN_PROCESS -> DISABLE
>   * L3: LD_ERR_FATAL_DETECT <--> LD_ERR_FATAL_DETECT
> - * LD_ERR_FATAL_DETECT -> SHUTDOWN_PROCESS
> + * LD_ERR_FATAL_DETECT -> DISABLE
>   */
>  static struct mhi_pm_transitions const dev_state_transitions[] = {
>   /* L0 States */
> @@ -72,7 +73,7 @@ static struct mhi_pm_transitions const 
> dev_state_transitions[] = {
>   {
>   MHI_PM_M3,
>   MHI_PM_M3_EXIT | MHI_PM_SYS_ERR_DETECT |
> - MHI_PM_SHUTDOWN_PROCESS | MHI_PM_LD_ERR_FATAL_DETECT
> + MHI_PM_LD_ERR_FATAL_DETECT
>   },
>   {
>   MHI_PM_M3_EXIT,
> @@ -103,7 +104,7 @@ static struct mhi_pm_transitions const 
> dev_state_transitions[] = {
>   /* L3 States */
>   {
>   MHI_PM_LD_ERR_FATAL_DETECT,
> - MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_SHUTDOWN_PROCESS
> + MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_DISABLE
>   },
>  };
>  
> @@ -670,6 +671,10 @@ void mhi_pm_st_worker(struct work_struct *work)
>   mhi_pm_disable_transition
>   (mhi_cntrl, MHI_PM_SHUTDOWN_PROCESS);
>   break;
> + case DEV_ST_TRANSITION_FATAL:
> + mhi_pm_disable_transition
> + (mhi_cntrl, MHI_PM_LD_ERR_FATAL_DETECT);
> + break;
>   default:
>   break;
>   }
> @@ -1039,6 +1044,7 @@ EXPORT_SYMBOL_GPL(mhi_async_power_up);
>  void mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful)
>  {
>   enum mhi_pm_state cur_state;
> + enum dev_st_transition next_state = DEV_ST_TRANSITION_DISABLE;
>   struct device *dev = &mhi_cntrl->mhi_dev->dev;
>  
>   /* If it's not a graceful shutdown, force MHI to linkdown state */
> @@ -1053,9 +1059,11 @@ void mhi_power_down(struct mhi_controller *mhi_cntrl, 
> bool graceful)
>   dev_dbg(dev, "Failed to move to state: %s from: %s\n",
>   to_mhi_pm_state_str(MHI_PM_LD_ERR_FATAL_DETECT),
>   to_mhi_pm_state_str(mhi_cntrl->pm_state));
> + else
> + next_state = DEV_ST_TRANSITION_FATAL;
>   }
>  
> - mhi_queue_state_transition(mhi_cntrl, DEV_ST_TRANSITION_DISABLE);
> + mhi_queue_state_transition(mhi_cntrl, next_state);
>  
>   /* Wait for shutdown to complete */
>   flush_work(&mhi_cntrl->st_worker);

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH v1 10/10] bus: mhi: core: Mark device inactive soon after host issues a shutdown

2020-10-10 Thread Manu Gautam


On 9/19/2020 7:32 AM, Bhaumik Bhatt wrote:
> Clients on the host may see the device in an active state for a short
> period of time after the host detects a device error or power down.

What scenario is referred as 'device error' here?
And power down is the non-graceful power_down by controller?

> Prevent any further host activity which could lead to race conditions
> or multiple callbacks to the controller or any timeouts seen by
> clients attempting to push data as they must be notified of the host
> intent sooner rather than later. This also allows the host and device
> states to be in sync with one another and prevents unnecessary host
> operations.
>
> Signed-off-by: Bhaumik Bhatt 
> ---
>  drivers/bus/mhi/core/main.c |  4 
>  drivers/bus/mhi/core/pm.c   | 31 +++
>  2 files changed, 23 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/bus/mhi/core/main.c b/drivers/bus/mhi/core/main.c
> index 1c8e332..5ec89e9 100644
> --- a/drivers/bus/mhi/core/main.c
> +++ b/drivers/bus/mhi/core/main.c
> @@ -400,6 +400,10 @@ irqreturn_t mhi_intvec_threaded_handler(int irq_number, 
> void *priv)
>  
>/* If device supports RDDM don't bother processing SYS error */
>   if (mhi_cntrl->rddm_image) {
> + /* host may be performing a device power down already */
> + if (!mhi_is_active(mhi_cntrl))
> + goto exit_intvec;
> +
>   if (mhi_cntrl->ee == MHI_EE_RDDM && mhi_cntrl->ee != ee) {
>   /* prevent clients from queueing any more packets */
>   write_lock_irq(&mhi_cntrl->pm_lock);
> diff --git a/drivers/bus/mhi/core/pm.c b/drivers/bus/mhi/core/pm.c
> index 16c04ab..4e2cb41 100644
> --- a/drivers/bus/mhi/core/pm.c
> +++ b/drivers/bus/mhi/core/pm.c
> @@ -469,15 +469,10 @@ static void mhi_pm_disable_transition(struct 
> mhi_controller *mhi_cntrl,
>   write_lock_irq(&mhi_cntrl->pm_lock);
>   prev_state = mhi_cntrl->pm_state;
>   cur_state = mhi_tryset_pm_state(mhi_cntrl, transition_state);
> - if (cur_state == transition_state) {
> - mhi_cntrl->ee = MHI_EE_DISABLE_TRANSITION;
> + if (cur_state == MHI_PM_SYS_ERR_PROCESS)
>   mhi_cntrl->dev_state = MHI_STATE_RESET;
> - }
>   write_unlock_irq(&mhi_cntrl->pm_lock);
>  
> - /* Wake up threads waiting for state transition */
> - wake_up_all(&mhi_cntrl->state_event);
> -
>   if (cur_state != transition_state) {
>   dev_err(dev, "Failed to transition to state: %s from: %s\n",
>   to_mhi_pm_state_str(transition_state),
> @@ -486,6 +481,11 @@ static void mhi_pm_disable_transition(struct 
> mhi_controller *mhi_cntrl,
>   return;
>   }
>  
> + mhi_cntrl->ee = MHI_EE_DISABLE_TRANSITION;
> +
> + /* Wake up threads waiting for state transition */
> + wake_up_all(&mhi_cntrl->state_event);
> +
>   /* Trigger MHI RESET so that the device will not access host memory */
>   if (MHI_REG_ACCESS_VALID(prev_state)) {
>   u32 in_reset = -1;
> @@ -1051,22 +1051,29 @@ void mhi_power_down(struct mhi_controller *mhi_cntrl, 
> bool graceful)
>   enum dev_st_transition next_state = DEV_ST_TRANSITION_DISABLE;
>   struct device *dev = &mhi_cntrl->mhi_dev->dev;
>  
> + mutex_lock(&mhi_cntrl->pm_mutex);
> + write_lock_irq(&mhi_cntrl->pm_lock);
> +
>   /* If it's not a graceful shutdown, force MHI to linkdown state */
>   if (!graceful) {
> - mutex_lock(&mhi_cntrl->pm_mutex);
> - write_lock_irq(&mhi_cntrl->pm_lock);
>   cur_state = mhi_tryset_pm_state(mhi_cntrl,
>   MHI_PM_LD_ERR_FATAL_DETECT);
> - write_unlock_irq(&mhi_cntrl->pm_lock);
> - mutex_unlock(&mhi_cntrl->pm_mutex);
> - if (cur_state != MHI_PM_LD_ERR_FATAL_DETECT)
> + if (cur_state != MHI_PM_LD_ERR_FATAL_DETECT) {
>   dev_dbg(dev, "Failed to move to state: %s from: %s\n",
>   to_mhi_pm_state_str(MHI_PM_LD_ERR_FATAL_DETECT),
>   to_mhi_pm_state_str(mhi_cntrl->pm_state));
> - else
> + } else {
>   next_state = DEV_ST_TRANSITION_FATAL;
> + wake_up_all(&mhi_cntrl->state_event);
> + }
>   }
>  
> + /* mark device inactive to avoid any further host processing */
> + mhi_cntrl->dev_state = MHI_STATE_RESET;
> +
> + write_unlock_irq(&mhi_cntrl->pm_lock);
> + mutex_unlock(&mhi_cntrl->pm_mutex);
> +
>   mhi_queue_state_transition(mhi_cntrl, next_state);
>  
>   /* Wait for shutdown to complete */

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH v7 2/4] usb: dwc3: qcom: Add interconnect support in dwc3 driver

2020-05-14 Thread Manu Gautam
Hi,

On 5/15/2020 9:27 AM, Viresh Kumar wrote:
> On Fri, 15 May 2020 at 02:33, Georgi Djakov  wrote:
>
>> ---8<---
>> diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
>> index 206caa0ea1c6..6661788b1a76 100644
>> --- a/drivers/usb/dwc3/Kconfig
>> +++ b/drivers/usb/dwc3/Kconfig
>> @@ -129,6 +129,7 @@ config USB_DWC3_QCOM
>> tristate "Qualcomm Platform"
>> depends on ARCH_QCOM || COMPILE_TEST
>> depends on EXTCON || !EXTCON
>> +   depends on INTERCONNECT || !INTERCONNECT
> Again, as I said yesterday. This looks incorrect and may not fix the problem..
>
> With this we will be able to select USB_DWC3_QCOM even when INTERCONNECT=m.

DWC3_QCOM in that case would be 'm' if INTERCONNECT =m and
that should be fine?


> What we perhaps need here is:
> depends on INTERCONNECT != m
>
> --
> viresh

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH] usb: dwc3: Support the dwc3 host suspend/resume

2017-07-21 Thread Manu Gautam
Hi,


On 7/21/2017 12:28 PM, Baolin Wang wrote:
> For some mobile devices with strict power management, we also want to
> suspend the host when the slave was detached for power saving. Thus
> adding the host suspend/resume functions to support this requirement.


USB/PM core already takes care of suspending root-HUB/XHCI when
no device connected.

>
> We will issue the pm_suspend_ignore_children() for the dwc3 device,
> since we will resume the child device (xHCI device) in runtime resume
> callback (dwc3_host_resume()) of dwc3 device, now the dwc3 device's
> runtime state is not RPM_ACTIVE, which will block to resume its
> child device (xHCI device). Add ignore children flag can avoid this
> situation.

This defeats the basic purpose of runtime PM. Without ignore_children
once USB bus is suspended, dwc3 gets suspended and then dwc3 glue device.
Only requirement I see from the patch is to resume XHCI/root-hub on
dwc3 resume. I am sure there must be other way to deal with that e.g.
doing same from glue driver by using a wq or use pm_request_resume()

>
> Signed-off-by: Baolin Wang 
> ---
>  drivers/usb/dwc3/core.c |   26 +-
>  drivers/usb/dwc3/core.h |7 +++
>  drivers/usb/dwc3/host.c |   15 +++
>  3 files changed, 47 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
> index 326b302..2be7ddc 100644
> --- a/drivers/usb/dwc3/core.c
> +++ b/drivers/usb/dwc3/core.c
> @@ -1193,6 +1193,7 @@ static int dwc3_probe(struct platform_device *pdev)
>   pm_runtime_use_autosuspend(dev);
>   pm_runtime_set_autosuspend_delay(dev, DWC3_DEFAULT_AUTOSUSPEND_DELAY);
>   pm_runtime_enable(dev);
> + pm_suspend_ignore_children(dev, true);
>   ret = pm_runtime_get_sync(dev);
>   if (ret < 0)
>   goto err1;
> @@ -1292,15 +1293,27 @@ static int dwc3_remove(struct platform_device *pdev)
>  static int dwc3_suspend_common(struct dwc3 *dwc)

What is the trigger for runtime suspend now that you have ignore_children set.
>  {
>   unsigned long   flags;
> + int ret;
>  
>   switch (dwc->dr_mode) {
>   case USB_DR_MODE_PERIPHERAL:
> + spin_lock_irqsave(&dwc->lock, flags);
> + dwc3_gadget_suspend(dwc);
> + spin_unlock_irqrestore(&dwc->lock, flags);
> + break;
>   case USB_DR_MODE_OTG:
> + ret = dwc3_host_suspend(dwc);
With DRD/OTG, if current mode is device and dwc3->xhci won't be valid.
You can refer to the patch that I pushed to address this.

> + if (ret)
> + return ret;
> +
>   spin_lock_irqsave(&dwc->lock, flags);
>   dwc3_gadget_suspend(dwc);
>   spin_unlock_irqrestore(&dwc->lock, flags);
>   break;
>   case USB_DR_MODE_HOST:
> + ret = dwc3_host_suspend(dwc);
> + if (ret)
> + return ret;
>   default:
>   /* do nothing */
>   break;
> @@ -1322,12 +1335,23 @@ static int dwc3_resume_common(struct dwc3 *dwc)
>  
>   switch (dwc->dr_mode) {
>   case USB_DR_MODE_PERIPHERAL:
> + spin_lock_irqsave(&dwc->lock, flags);
> + dwc3_gadget_resume(dwc);
> + spin_unlock_irqrestore(&dwc->lock, flags);
> + break;
>   case USB_DR_MODE_OTG:
> + ret = dwc3_host_resume(dwc);
> + if (ret)
> + return ret;
> +
>   spin_lock_irqsave(&dwc->lock, flags);
>   dwc3_gadget_resume(dwc);
>   spin_unlock_irqrestore(&dwc->lock, flags);
> - /* FALLTHROUGH */
> + break;
>   case USB_DR_MODE_HOST:
> + ret = dwc3_host_resume(dwc);
> + if (ret)
> + return ret;
>   default:
>   /* do nothing */
>   break;
> diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
> index ea910ac..9b5a4eb 100644
> --- a/drivers/usb/dwc3/core.h
> +++ b/drivers/usb/dwc3/core.h
> @@ -1193,11 +1193,18 @@ static inline bool dwc3_is_usb31(struct dwc3 *dwc)
>  #if IS_ENABLED(CONFIG_USB_DWC3_HOST) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
>  int dwc3_host_init(struct dwc3 *dwc);
>  void dwc3_host_exit(struct dwc3 *dwc);
> +int dwc3_host_suspend(struct dwc3 *dwc);
> +int dwc3_host_resume(struct dwc3 *dwc);
>  #else
>  static inline int dwc3_host_init(struct dwc3 *dwc)
>  { return 0; }
>  static inline void dwc3_host_exit(struct dwc3 *dwc)
>  { }
> +
> +static inline int dwc3_host_suspend(struct dwc3 *dwc)
> +{ return 0; }
> +static inline int dwc3_host_resume(struct dwc3 *dwc)
> +{ return 0; }
>  #endif
>  
>  #if IS_ENABLED(CONFIG_USB_DWC3_GADGET) || 
> IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
> diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
> index 76f0b0d..3fa4414 100644
> --- a/drivers/usb/dwc3/host.c
> +++ b/drivers/usb/dwc3/host.c
> @@ -16,6 +16,7 @@
>   */
>  
>  #include 
> +#i

Re: [PATCH] usb: dwc3: Support the dwc3 host suspend/resume

2017-07-21 Thread Manu Gautam
Hi,

On 7/21/2017 2:31 PM, Baolin Wang wrote:
> On 21 July 2017 at 16:45, Manu Gautam  wrote:
>> Hi,
>>
>>
>> On 7/21/2017 12:28 PM, Baolin Wang wrote:
>>> For some mobile devices with strict power management, we also want to
>>> suspend the host when the slave was detached for power saving. Thus
>>> adding the host suspend/resume functions to support this requirement.
>>
>> USB/PM core already takes care of suspending root-HUB/XHCI when
>> no device connected.
> Correct, but what I mean is we can power off the dwc3 controller when
> there are no device connected.
>
>>> We will issue the pm_suspend_ignore_children() for the dwc3 device,
>>> since we will resume the child device (xHCI device) in runtime resume
>>> callback (dwc3_host_resume()) of dwc3 device, now the dwc3 device's
>>> runtime state is not RPM_ACTIVE, which will block to resume its
>>> child device (xHCI device). Add ignore children flag can avoid this
>>> situation.
>> This defeats the basic purpose of runtime PM. Without ignore_children
>> once USB bus is suspended, dwc3 gets suspended and then dwc3 glue device.
>> Only requirement I see from the patch is to resume XHCI/root-hub on
>> dwc3 resume. I am sure there must be other way to deal with that e.g.
>> doing same from glue driver by using a wq or use pm_request_resume()
> Ah, I will try pm_request_resume().
>
>>> Signed-off-by: Baolin Wang 
>>> ---
>>>  drivers/usb/dwc3/core.c |   26 +-
>>>  drivers/usb/dwc3/core.h |7 +++
>>>  drivers/usb/dwc3/host.c |   15 +++
>>>  3 files changed, 47 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
>>> index 326b302..2be7ddc 100644
>>> --- a/drivers/usb/dwc3/core.c
>>> +++ b/drivers/usb/dwc3/core.c
>>> @@ -1193,6 +1193,7 @@ static int dwc3_probe(struct platform_device *pdev)
>>>   pm_runtime_use_autosuspend(dev);
>>>   pm_runtime_set_autosuspend_delay(dev, DWC3_DEFAULT_AUTOSUSPEND_DELAY);
>>>   pm_runtime_enable(dev);
>>> + pm_suspend_ignore_children(dev, true);
>>>   ret = pm_runtime_get_sync(dev);
>>>   if (ret < 0)
>>>   goto err1;
>>> @@ -1292,15 +1293,27 @@ static int dwc3_remove(struct platform_device *pdev)
>>>  static int dwc3_suspend_common(struct dwc3 *dwc)
>> What is the trigger for runtime suspend now that you have ignore_children 
>> set.
>>>  {
>>>   unsigned long   flags;
>>> + int ret;
>>>
>>>   switch (dwc->dr_mode) {
>>>   case USB_DR_MODE_PERIPHERAL:
>>> + spin_lock_irqsave(&dwc->lock, flags);
>>> + dwc3_gadget_suspend(dwc);
>>> + spin_unlock_irqrestore(&dwc->lock, flags);
>>> + break;
>>>   case USB_DR_MODE_OTG:
>>> + ret = dwc3_host_suspend(dwc);
>> With DRD/OTG, if current mode is device and dwc3->xhci won't be valid.
> If current mode is device, then xHCI device is always in suspend state.
dwc->xhci is allocated in dwc3_host_init. And dwc->xhci device is unregistred
from dwc3_host_exit that is called from __dwc3_set_mode.
>
>> You can refer to the patch that I pushed to address this.
>>
>>> + if (ret)
>>> + return ret;
>>> +
>>>   spin_lock_irqsave(&dwc->lock, flags);
>>>   dwc3_gadget_suspend(dwc);
>>>   spin_unlock_irqrestore(&dwc->lock, flags);
>>>   break;
>>>   case USB_DR_MODE_HOST:
>>> + ret = dwc3_host_suspend(dwc);
>>> + if (ret)
>>> + return ret;
>>>   default:
>>>   /* do nothing */
>>>   break;
>>> @@ -1322,12 +1335,23 @@ static int dwc3_resume_common(struct dwc3 *dwc)
>>>
>>>   switch (dwc->dr_mode) {
>>>   case USB_DR_MODE_PERIPHERAL:
>>> + spin_lock_irqsave(&dwc->lock, flags);
>>> + dwc3_gadget_resume(dwc);
>>> + spin_unlock_irqrestore(&dwc->lock, flags);
>>> + break;
>>>   case USB_DR_MODE_OTG:
>>> + ret = dwc3_host_resume(dwc);
>>> + if (ret)
>>> + return ret;
>>> +
>>>   spin_lock_irqsave(&dwc->l

[PATCH v1 1/6] phy: qcom-qmp: Fix phy pipe clock gating

2017-07-21 Thread Manu Gautam
From: Vivek Gautam 

Pipe clock comes out of the phy and is available as long as
the phy is turned on. Clock controller fails to gate this
clock after the phy is turned off and generates a warning.

/ # [   33.048561] gcc_usb3_phy_pipe_clk status stuck at 'on'
[   33.048585] [ cut here ]
[   33.052621] WARNING: CPU: 1 PID: 18 at ../drivers/clk/qcom/clk-branch.c:97 
clk_branch_wait+0xf0/0x108
[   33.057384] Modules linked in:
[   33.066497] CPU: 1 PID: 18 Comm: kworker/1:0 Tainted: GW   
4.12.0-rc7-00024-gfe926e34c36d-dirty #96
[   33.069451] Hardware name: Qualcomm Technologies, Inc. DB820c (DT)
...
[   33.278565] [] clk_branch_wait+0xf0/0x108
[   33.286375] [] clk_branch2_disable+0x28/0x34
[   33.291761] [] clk_core_disable+0x5c/0x88
[   33.297660] [] clk_core_disable_lock+0x20/0x34
[   33.303129] [] clk_disable+0x1c/0x24
[   33.309384] [] qcom_qmp_phy_poweroff+0x20/0x48
[   33.314328] [] phy_power_off+0x80/0xdc
[   33.320492] [] dwc3_core_exit+0x94/0xa0
[   33.325784] [] dwc3_suspend_common+0x50/0x60
[   33.331080] [] dwc3_runtime_suspend+0x48/0x6c
[   33.336810] [] pm_generic_runtime_suspend+0x28/0x38
[   33.342627] [] __rpm_callback+0x150/0x254
[   33.349222] [] rpm_callback+0x24/0x78
[   33.354604] [] rpm_suspend+0xe0/0x4e4
[   33.359813] [] pm_runtime_work+0xdc/0xf0
[   33.365028] [] process_one_work+0x12c/0x28c
[   33.370576] [] worker_thread+0x58/0x3b8
[   33.376393] [] kthread+0x100/0x12c
[   33.381776] [] ret_from_fork+0x10/0x50

Fix this by enabling pipe clock at the end of phy_init(), and disabling
it as the first thing in phy_exit().

Fixes: e78f3d15e115 ("phy: qcom-qmp: new qmp phy driver for qcom-chipsets")

Signed-off-by: Vivek Gautam 

diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c 
b/drivers/phy/qualcomm/phy-qcom-qmp.c
index 78ca628..a230c7b 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.c
@@ -610,19 +610,10 @@ static int qcom_qmp_phy_poweron(struct phy *phy)
 
/* turn on regulator supplies */
ret = regulator_bulk_enable(num, qmp->vregs);
-   if (ret) {
+   if (ret)
dev_err(qmp->dev, "failed to enable regulators, err=%d\n", ret);
-   return ret;
-   }
-
-   ret = clk_prepare_enable(qphy->pipe_clk);
-   if (ret) {
-   dev_err(qmp->dev, "pipe_clk enable failed, err=%d\n", ret);
-   regulator_bulk_disable(num, qmp->vregs);
-   return ret;
-   }
 
-   return 0;
+   return ret;
 }
 
 static int qcom_qmp_phy_poweroff(struct phy *phy)
@@ -630,8 +621,6 @@ static int qcom_qmp_phy_poweroff(struct phy *phy)
struct qmp_phy *qphy = phy_get_drvdata(phy);
struct qcom_qmp *qmp = qphy->qmp;
 
-   clk_disable_unprepare(qphy->pipe_clk);
-
regulator_bulk_disable(qmp->cfg->num_vregs, qmp->vregs);
 
return 0;
@@ -797,7 +786,14 @@ static int qcom_qmp_phy_init(struct phy *phy)
goto err_pcs_ready;
}
 
-   return ret;
+   /* phy is initialized; we can turn on the pipe clock now */
+   ret = clk_prepare_enable(qphy->pipe_clk);
+   if (ret) {
+   dev_err(qmp->dev, "pipe_clk enable failed, err=%d\n", ret);
+   goto err_pcs_ready;
+   }
+
+   return 0;
 
 err_pcs_ready:
if (cfg->has_lane_rst)
@@ -818,6 +814,8 @@ static int qcom_qmp_phy_exit(struct phy *phy)
const struct qmp_phy_cfg *cfg = qmp->cfg;
int i = cfg->num_clks;
 
+   clk_disable_unprepare(qphy->pipe_clk);
+
/* PHY reset */
qphy_setbits(qphy->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,\na 
Linux Foundation Collaborative Project



[PATCH v1 2/6] phy: qcom-qmp: Power-on PHY before initialization

2017-07-21 Thread Manu Gautam
PHY must be powered on before turning ON clocks and
attempting to initialize it. Driver is exposing
separate init and power_on routines for this.
Apparently USB dwc3 core driver performs power-on
after init. Also, poweron and init for QMP PHY
need to be executed together always, hence remove
poweron callback from phy_ops and explicitly perform
this from init, similar changes needed for poweroff.

Signed-off-by: Manu Gautam 

diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c 
b/drivers/phy/qualcomm/phy-qcom-qmp.c
index a230c7b..aefb853 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.c
@@ -479,6 +479,8 @@ struct qcom_qmp {
 
struct mutex phy_mutex;
int init_count;
+   bool power_enabled;
+   bool clk_enabled;
 };
 
 static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val)
@@ -599,29 +601,69 @@ static void qcom_qmp_phy_configure(void __iomem *base,
}
 }
 
-static int qcom_qmp_phy_poweron(struct phy *phy)
+static int qcom_qmp_phy_poweron(struct qcom_qmp *qmp)
 {
-   struct qmp_phy *qphy = phy_get_drvdata(phy);
-   struct qcom_qmp *qmp = qphy->qmp;
int num = qmp->cfg->num_vregs;
int ret;
 
-   dev_vdbg(&phy->dev, "Powering on QMP phy\n");
+   dev_vdbg(qmp->dev, "Powering on QMP phy\n");
+
+   if (qmp->power_enabled)
+   return 0;
 
/* turn on regulator supplies */
ret = regulator_bulk_enable(num, qmp->vregs);
if (ret)
dev_err(qmp->dev, "failed to enable regulators, err=%d\n", ret);
+   else
+   qmp->power_enabled = true;
 
return ret;
 }
 
-static int qcom_qmp_phy_poweroff(struct phy *phy)
+static int qcom_qmp_phy_poweroff(struct qcom_qmp *qmp)
 {
-   struct qmp_phy *qphy = phy_get_drvdata(phy);
-   struct qcom_qmp *qmp = qphy->qmp;
+   if (!qmp->power_enabled)
+   return 0;
 
regulator_bulk_disable(qmp->cfg->num_vregs, qmp->vregs);
+   qmp->power_enabled = false;
+
+   return 0;
+}
+
+static int qcom_qmp_phy_enable_clocks(struct qcom_qmp *qmp)
+{
+   int ret = 0, i;
+
+   if (qmp->clk_enabled)
+   return 0;
+
+   for (i = 0; i < qmp->cfg->num_clks; i++) {
+   ret = clk_prepare_enable(qmp->clks[i]);
+   if (ret) {
+   dev_err(qmp->dev, "failed to enable %s clk, err=%d\n",
+   qmp->cfg->clk_list[i], ret);
+   while (--i >= 0)
+   clk_disable_unprepare(qmp->clks[i]);
+   }
+   }
+   qmp->clk_enabled = true;
+
+   return ret;
+}
+
+static int qcom_qmp_phy_disable_clocks(struct qcom_qmp *qmp)
+{
+   int i = qmp->cfg->num_clks;
+
+   if (!qmp->clk_enabled)
+   return 0;
+
+   while (--i >= 0)
+   clk_disable_unprepare(qmp->clks[i]);
+
+   qmp->clk_enabled = false;
 
return 0;
 }
@@ -729,19 +771,17 @@ static int qcom_qmp_phy_init(struct phy *phy)
void __iomem *pcs = qphy->pcs;
void __iomem *status;
unsigned int mask, val;
-   int ret, i;
+   int ret;
 
dev_vdbg(qmp->dev, "Initializing QMP phy\n");
 
-   for (i = 0; i < qmp->cfg->num_clks; i++) {
-   ret = clk_prepare_enable(qmp->clks[i]);
-   if (ret) {
-   dev_err(qmp->dev, "failed to enable %s clk, err=%d\n",
-   qmp->cfg->clk_list[i], ret);
-   while (--i >= 0)
-   clk_disable_unprepare(qmp->clks[i]);
-   }
-   }
+   ret = qcom_qmp_phy_poweron(qmp);
+   if (ret)
+   return ret;
+
+   ret = qcom_qmp_phy_enable_clocks(qmp);
+   if (ret)
+   goto err_clk_enable;
 
ret = qcom_qmp_phy_com_init(qmp);
if (ret)
@@ -801,8 +841,9 @@ static int qcom_qmp_phy_init(struct phy *phy)
 err_lane_rst:
qcom_qmp_phy_com_exit(qmp);
 err_com_init:
-   while (--i >= 0)
-   clk_disable_unprepare(qmp->clks[i]);
+   qcom_qmp_phy_disable_clocks(qmp);
+err_clk_enable:
+   qcom_qmp_phy_poweroff(qmp);
 
return ret;
 }
@@ -812,7 +853,6 @@ static int qcom_qmp_phy_exit(struct phy *phy)
struct qmp_phy *qphy = phy_get_drvdata(phy);
struct qcom_qmp *qmp = qphy->qmp;
const struct qmp_phy_cfg *cfg = qmp->cfg;
-   int i = cfg->num_clks;
 
clk_disable_unprepare(qphy->pipe_clk);
 
@@ -830,8 +870,9 @@ static int qcom_qmp_phy_exit(struct phy *phy)
 
qcom_qmp_phy_com_exit(qmp);
 
-   while (--i >= 0)
-   clk_disable_unprepare(qmp->clks[i]);
+   qcom_qmp_phy_disable_clocks(qmp);
+
+   qcom_qmp_phy_po

[PATCH v1 3/6] phy: qcom-qusb2: Power-on PHY before initialization

2017-07-21 Thread Manu Gautam
PHY must be powered on before turning ON clocks and
attempting to initialize it. Driver is exposing
separate init and power_on routines for this.
Apparently USB dwc3 core driver performs power-on
after init. Also, poweron and init for QUSB2 PHY
need to be executed together always, hence remove
poweron callback from phy_ops and explicitly perform
this from init, similar changes needed for poweroff.

Signed-off-by: Manu Gautam 

diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c 
b/drivers/phy/qualcomm/phy-qcom-qusb2.c
index 6c57524..fa60a99 100644
--- a/drivers/phy/qualcomm/phy-qcom-qusb2.c
+++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c
@@ -195,13 +195,13 @@ static void qusb2_phy_set_tune2_param(struct qusb2_phy 
*qphy)
qusb2_setbits(qphy->base, QUSB2PHY_PORT_TUNE2, val[0] << 0x4);
 }
 
-static int qusb2_phy_poweron(struct phy *phy)
+static int qusb2_phy_poweron(struct qusb2_phy *qphy)
 {
-   struct qusb2_phy *qphy = phy_get_drvdata(phy);
+   struct device *dev = &qphy->phy->dev;
int num = ARRAY_SIZE(qphy->vregs);
int ret;
 
-   dev_vdbg(&phy->dev, "%s(): Powering-on QUSB2 phy\n", __func__);
+   dev_vdbg(dev, "%s(): Powering-on QUSB2 phy\n", __func__);
 
/* turn on regulator supplies */
ret = regulator_bulk_enable(num, qphy->vregs);
@@ -210,7 +210,7 @@ static int qusb2_phy_poweron(struct phy *phy)
 
ret = clk_prepare_enable(qphy->iface_clk);
if (ret) {
-   dev_err(&phy->dev, "failed to enable iface_clk, %d\n", ret);
+   dev_err(dev, "failed to enable iface_clk, %d\n", ret);
regulator_bulk_disable(num, qphy->vregs);
return ret;
}
@@ -218,10 +218,8 @@ static int qusb2_phy_poweron(struct phy *phy)
return 0;
 }
 
-static int qusb2_phy_poweroff(struct phy *phy)
+static int qusb2_phy_poweroff(struct qusb2_phy *qphy)
 {
-   struct qusb2_phy *qphy = phy_get_drvdata(phy);
-
clk_disable_unprepare(qphy->iface_clk);
 
regulator_bulk_disable(ARRAY_SIZE(qphy->vregs), qphy->vregs);
@@ -238,11 +236,15 @@ static int qusb2_phy_init(struct phy *phy)
 
dev_vdbg(&phy->dev, "%s(): Initializing QUSB2 phy\n", __func__);
 
+   ret = qusb2_phy_poweron(qphy);
+   if (ret)
+   return ret;
+
/* enable ahb interface clock to program phy */
ret = clk_prepare_enable(qphy->cfg_ahb_clk);
if (ret) {
dev_err(&phy->dev, "failed to enable cfg ahb clock, %d\n", ret);
-   return ret;
+   goto poweroff_phy;
}
 
/* Perform phy reset */
@@ -344,6 +346,9 @@ static int qusb2_phy_init(struct phy *phy)
reset_control_assert(qphy->phy_reset);
 disable_ahb_clk:
clk_disable_unprepare(qphy->cfg_ahb_clk);
+poweroff_phy:
+   qusb2_phy_poweroff(qphy);
+
return ret;
 }
 
@@ -362,14 +367,14 @@ static int qusb2_phy_exit(struct phy *phy)
 
clk_disable_unprepare(qphy->cfg_ahb_clk);
 
+   qusb2_phy_poweroff(qphy);
+
return 0;
 }
 
 static const struct phy_ops qusb2_phy_gen_ops = {
.init   = qusb2_phy_init,
.exit   = qusb2_phy_exit,
-   .power_on   = qusb2_phy_poweron,
-   .power_off  = qusb2_phy_poweroff,
.owner  = THIS_MODULE,
 };
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,\na 
Linux Foundation Collaborative Project



[PATCH v1 4/6] phy: qcom-qusb2: Add support for runtime PM

2017-07-21 Thread Manu Gautam
Driver can turn off clocks during runtime suspend.
Also, runtime suspend is not as a result of host mode
selective suspend then PHY can be powered off as well.

Signed-off-by: Manu Gautam 

diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c 
b/drivers/phy/qualcomm/phy-qcom-qusb2.c
index fa60a99..b505681 100644
--- a/drivers/phy/qualcomm/phy-qcom-qusb2.c
+++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c
@@ -132,6 +132,9 @@ struct qusb2_phy {
 
const struct qusb2_phy_cfg *cfg;
bool has_se_clk_scheme;
+   bool phy_initialized;
+   bool powered_on;
+   enum phy_mode mode;
 };
 
 static inline void qusb2_setbits(void __iomem *base, u32 offset, u32 val)
@@ -203,30 +206,111 @@ static int qusb2_phy_poweron(struct qusb2_phy *qphy)
 
dev_vdbg(dev, "%s(): Powering-on QUSB2 phy\n", __func__);
 
+   if (qphy->powered_on)
+   return 0;
+
/* turn on regulator supplies */
ret = regulator_bulk_enable(num, qphy->vregs);
if (ret)
return ret;
 
-   ret = clk_prepare_enable(qphy->iface_clk);
-   if (ret) {
-   dev_err(dev, "failed to enable iface_clk, %d\n", ret);
-   regulator_bulk_disable(num, qphy->vregs);
-   return ret;
-   }
+   qphy->powered_on = true;
 
return 0;
 }
 
 static int qusb2_phy_poweroff(struct qusb2_phy *qphy)
 {
-   clk_disable_unprepare(qphy->iface_clk);
+   if (!qphy->powered_on)
+   return 0;
 
regulator_bulk_disable(ARRAY_SIZE(qphy->vregs), qphy->vregs);
 
+   qphy->powered_on = false;
+
+   return 0;
+}
+
+static int qusb2_phy_set_mode(struct phy *phy, enum phy_mode mode)
+{
+   struct qusb2_phy *qphy = phy_get_drvdata(phy);
+
+   qphy->mode = mode;
+
return 0;
 }
 
+static int __maybe_unused qusb2_phy_runtime_suspend(struct device *dev)
+{
+   struct qusb2_phy *qphy = dev_get_drvdata(dev);
+
+   dev_vdbg(dev, "Suspending QUSB2 Phy, mode:%d\n", qphy->mode);
+
+   if (!qphy->phy_initialized) {
+   dev_vdbg(dev, "PHY not initialized, bailing out\n");
+   return 0;
+   }
+
+   if (!qphy->has_se_clk_scheme)
+   clk_disable_unprepare(qphy->ref_clk);
+
+   clk_disable_unprepare(qphy->cfg_ahb_clk);
+   clk_disable_unprepare(qphy->iface_clk);
+
+   if (qphy->mode == PHY_MODE_INVALID)
+   qusb2_phy_poweroff(qphy);
+
+   return 0;
+}
+
+static int __maybe_unused qusb2_phy_runtime_resume(struct device *dev)
+{
+   struct qusb2_phy *qphy = dev_get_drvdata(dev);
+   int ret;
+
+   dev_vdbg(dev, "Resuming QUSB2 phy, mode:%d\n", qphy->mode);
+
+   if (!qphy->phy_initialized) {
+   dev_vdbg(dev, "PHY not initialized, bailing out\n");
+   return 0;
+   }
+
+   ret = qusb2_phy_poweron(qphy);
+   if (ret)
+   return ret;
+
+   ret = clk_prepare_enable(qphy->iface_clk);
+   if (ret) {
+   dev_err(dev, "failed to enable iface_clk, %d\n", ret);
+   goto poweroff_phy;
+   }
+
+   ret = clk_prepare_enable(qphy->cfg_ahb_clk);
+   if (ret) {
+   dev_err(dev, "failed to enable cfg ahb clock, %d\n", ret);
+   goto disable_iface_clk;
+   }
+
+   if (!qphy->has_se_clk_scheme) {
+   clk_prepare_enable(qphy->ref_clk);
+   if (ret) {
+   dev_err(dev, "failed to enable ref clk, %d\n", ret);
+   goto disable_ahb_clk;
+   }
+   }
+
+   return 0;
+
+disable_ahb_clk:
+   clk_disable_unprepare(qphy->cfg_ahb_clk);
+disable_iface_clk:
+   clk_disable_unprepare(qphy->iface_clk);
+poweroff_phy:
+   qusb2_phy_poweroff(qphy);
+
+   return ret;
+}
+
 static int qusb2_phy_init(struct phy *phy)
 {
struct qusb2_phy *qphy = phy_get_drvdata(phy);
@@ -240,11 +324,17 @@ static int qusb2_phy_init(struct phy *phy)
if (ret)
return ret;
 
+   ret = clk_prepare_enable(qphy->iface_clk);
+   if (ret) {
+   dev_err(&phy->dev, "failed to enable iface_clk, %d\n", ret);
+   goto poweroff_phy;
+   }
+
/* enable ahb interface clock to program phy */
ret = clk_prepare_enable(qphy->cfg_ahb_clk);
if (ret) {
dev_err(&phy->dev, "failed to enable cfg ahb clock, %d\n", ret);
-   goto poweroff_phy;
+   goto disable_iface_clk;
}
 
/* Perform phy reset */
@@ -336,6 +426,7 @@ static int qusb2_phy_init(struct phy *phy)
ret = -EBUSY;
goto disable_ref_clk;
}
+   qphy->phy_initialized = true;
 
return 0;
 
@@ -346,6 +437,8 @@ static int qusb2_phy_init(st

[PATCH v1 6/6] usb: dwc3: core: Notify USB3 PHY as well for DRD modes

2017-07-21 Thread Manu Gautam
Driver currently notifies only USB3 PHY for mode change.
Extend this to USB3 PHY so that driver based on the mode
can release system resources - clocks, regulators etc.
and can even turn off PHY during runtime suspend.

Signed-off-by: Manu Gautam 

diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 326b302..1f6c51e 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -156,9 +156,8 @@ static void __dwc3_set_mode(struct work_struct *work)
} else {
if (dwc->usb2_phy)
otg_set_vbus(dwc->usb2_phy->otg, true);
-   if (dwc->usb2_generic_phy)
-   phy_set_mode(dwc->usb2_generic_phy, 
PHY_MODE_USB_HOST);
-
+   phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
+   phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST);
}
break;
case DWC3_GCTL_PRTCAP_DEVICE:
@@ -166,8 +165,8 @@ static void __dwc3_set_mode(struct work_struct *work)
 
if (dwc->usb2_phy)
otg_set_vbus(dwc->usb2_phy->otg, false);
-   if (dwc->usb2_generic_phy)
-   phy_set_mode(dwc->usb2_generic_phy, 
PHY_MODE_USB_DEVICE);
+   phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE);
+   phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE);
 
ret = dwc3_gadget_init(dwc);
if (ret)
@@ -931,8 +930,8 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
 
if (dwc->usb2_phy)
otg_set_vbus(dwc->usb2_phy->otg, false);
-   if (dwc->usb2_generic_phy)
-   phy_set_mode(dwc->usb2_generic_phy, 
PHY_MODE_USB_DEVICE);
+   phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE);
+   phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE);
 
ret = dwc3_gadget_init(dwc);
if (ret) {
@@ -946,8 +945,8 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
 
if (dwc->usb2_phy)
otg_set_vbus(dwc->usb2_phy->otg, true);
-   if (dwc->usb2_generic_phy)
-   phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
+   phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
+   phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST);
 
ret = dwc3_host_init(dwc);
if (ret) {
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,\na 
Linux Foundation Collaborative Project



[PATCH v1 5/6] phy: qcom-qmp: Add support for runtime PM

2017-07-21 Thread Manu Gautam
Driver can turn off clocks during runtime suspend.
Also, runtime suspend is not as a result of host mode
selective suspend then PHY can be powered off as well.

Signed-off-by: Manu Gautam 

diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c 
b/drivers/phy/qualcomm/phy-qcom-qmp.c
index aefb853..8394e24 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.c
@@ -481,6 +481,8 @@ struct qcom_qmp {
int init_count;
bool power_enabled;
bool clk_enabled;
+   bool phy_initialized;
+   enum phy_mode mode;
 };
 
 static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val)
@@ -832,6 +834,7 @@ static int qcom_qmp_phy_init(struct phy *phy)
dev_err(qmp->dev, "pipe_clk enable failed, err=%d\n", ret);
goto err_pcs_ready;
}
+   qmp->phy_initialized = true;
 
return 0;
 
@@ -874,6 +877,75 @@ static int qcom_qmp_phy_exit(struct phy *phy)
 
qcom_qmp_phy_poweroff(qmp);
 
+   qmp->phy_initialized = false;
+
+   return 0;
+}
+
+static int qcom_qmp_phy_set_mode(struct phy *phy, enum phy_mode mode)
+{
+   struct qmp_phy *qphy = phy_get_drvdata(phy);
+   struct qcom_qmp *qmp = qphy->qmp;
+
+   qmp->mode = mode;
+
+   return 0;
+}
+
+static int __maybe_unused qcom_qmp_phy_runtime_suspend(struct device *dev)
+{
+   struct qcom_qmp *qmp = dev_get_drvdata(dev);
+   struct qmp_phy *qphy = qmp->phys[0];
+   const struct qmp_phy_cfg *cfg = qmp->cfg;
+   void __iomem *pcs = qphy->pcs;
+
+   dev_vdbg(dev, "Suspending QMP phy, mode:%d\n", qmp->mode);
+
+   if (!qmp->phy_initialized) {
+   dev_vdbg(dev, "PHY not initialized, bailing out\n");
+   return 0;
+   }
+
+   /* Power down PHY if not in session */
+   if (qmp->mode == PHY_MODE_INVALID)
+   qphy_clrbits(pcs, QPHY_POWER_DOWN_CONTROL, cfg->pwrdn_ctrl);
+
+   clk_disable_unprepare(qphy->pipe_clk);
+   qcom_qmp_phy_disable_clocks(qmp);
+
+   if (qmp->mode == PHY_MODE_INVALID)
+   qcom_qmp_phy_poweroff(qmp);
+
+   return 0;
+}
+
+static int __maybe_unused qcom_qmp_phy_runtime_resume(struct device *dev)
+{
+   struct qcom_qmp *qmp = dev_get_drvdata(dev);
+   struct qmp_phy *qphy = qmp->phys[0];
+   const struct qmp_phy_cfg *cfg = qmp->cfg;
+   void __iomem *pcs = qphy->pcs;
+   int ret = 0;
+
+   dev_vdbg(dev, "Resuming QMP phy, mode:%d\n", qmp->mode);
+
+   if (!qmp->phy_initialized) {
+   dev_vdbg(dev, "PHY not initialized, bailing out\n");
+   return 0;
+   }
+
+   qcom_qmp_phy_poweron(qmp);
+
+   qcom_qmp_phy_enable_clocks(qmp);
+
+   ret = clk_prepare_enable(qphy->pipe_clk);
+   if (ret) {
+   dev_err(dev, "pipe_clk enable failed, err=%d\n", ret);
+   return ret;
+   }
+
+   qphy_setbits(pcs, QPHY_POWER_DOWN_CONTROL, cfg->pwrdn_ctrl);
+
return 0;
 }
 
@@ -999,6 +1071,7 @@ static int phy_pipe_clk_register(struct qcom_qmp *qmp, int 
id)
 static const struct phy_ops qcom_qmp_phy_gen_ops = {
.init   = qcom_qmp_phy_init,
.exit   = qcom_qmp_phy_exit,
+   .set_mode   = qcom_qmp_phy_set_mode,
.owner  = THIS_MODULE,
 };
 
@@ -1091,6 +1164,11 @@ int qcom_qmp_phy_create(struct device *dev, struct 
device_node *np, int id)
 };
 MODULE_DEVICE_TABLE(of, qcom_qmp_phy_of_match_table);
 
+static const struct dev_pm_ops qcom_qmp_phy_pm_ops = {
+   SET_RUNTIME_PM_OPS(qcom_qmp_phy_runtime_suspend,
+  qcom_qmp_phy_runtime_resume, NULL)
+};
+
 static int qcom_qmp_phy_probe(struct platform_device *pdev)
 {
struct qcom_qmp *qmp;
@@ -1118,6 +1196,7 @@ static int qcom_qmp_phy_probe(struct platform_device 
*pdev)
qmp->serdes = base;
 
mutex_init(&qmp->phy_mutex);
+   qmp->mode = PHY_MODE_INVALID;
 
/* Get the specific init parameters of QMP phy */
qmp->cfg = of_device_get_match_data(dev);
@@ -1146,12 +1225,16 @@ static int qcom_qmp_phy_probe(struct platform_device 
*pdev)
return -ENOMEM;
 
id = 0;
+   pm_runtime_set_active(dev);
+   pm_runtime_enable(dev);
+
for_each_available_child_of_node(dev->of_node, child) {
/* Create per-lane phy */
ret = qcom_qmp_phy_create(dev, child, id);
if (ret) {
dev_err(dev, "failed to create lane%d phy, %d\n",
id, ret);
+   pm_runtime_disable(dev);
return ret;
}
 
@@ -1163,6 +1246,7 @@ static int qcom_qmp_phy_probe(struct platform_device 
*pdev)
if (ret) {
dev_err(qmp->dev,
   

Re: [PATCH v3 14/16] phy: Add notify_speed callback

2017-12-28 Thread Manu Gautam
Hi,


On 12/28/2017 4:34 PM, Kishon Vijay Abraham I wrote:
> Hi,
>
[snip]
>
>>> I'd prefer adding modes in enum phy_mode according to speed and using 
>>> phy_set_mode.
>> yeah, that also seems good idea. How about something like this:
>>
>> --- a/include/linux/phy/phy.h
>> +++ b/include/linux/phy/phy.h
>> @@ -23,12 +23,16 @@
>>  struct phy;
>>  
>>  enum phy_mode {
>> -PHY_MODE_INVALID,
>> -PHY_MODE_USB_HOST,
>> -PHY_MODE_USB_DEVICE,
>> -PHY_MODE_USB_OTG,
>> -PHY_MODE_SGMII,
>> -PHY_MODE_10GKR,
>> +PHY_MODE_INVALID= 0,
>> +PHY_MODE_USB_HOST   = BIT(0),
>> +PHY_MODE_USB_DEVICE = BIT(1),
>> +PHY_MODE_USB_OTG,   = BIT(2),
>> +PHY_MODE_SGMII  = BIT(3),
>> +PHY_MODE_10GKR  = BIT(4),
>> +PHY_MODE_USB_LS = BIT(5),
>> +PHY_MODE_USB_FS = BIT(6),
>> +PHY_MODE_USB_HS = BIT(7),
>> +PHY_MODE_USB_SS = BIT(8),
>>  };
>>
>>
>> This way I don't need to duplicate USB speed enums for host/device or otg 
>> modes.
> no.. let's keep enum. It's lot more cleaner IMO.

In that case all PHY drivers would need to consider these speed enums. E.g.

if (mode == HOST) check in PHY driver would need to be changed to:
if (mode == HOST || mode == HOST_LS || mode == HOST_FS || mode == HOST_HS ||
    mode == HOST_SS

This looks clumsy.
Where as if bits to used then there is no need for such changes.

>
> Thanks
> Kishon
> --
> To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
> the body of a message to majord...@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH v3 14/16] phy: Add notify_speed callback

2018-01-01 Thread Manu Gautam
Hi,


On 12/29/2017 11:58 AM, Kishon Vijay Abraham I wrote:
> Hi,
>
> On Friday 29 December 2017 09:54 AM, Manu Gautam wrote:
>> Hi,
[snip]
>
> suggest using switch in such case.. and not all PHY drivers do specific
> configurations for specific speeds.
>> This looks clumsy.
>> Where as if bits to used then there is no need for such changes.
> really? using bits should only make it more clumsy.

Thanks for your feedback. I will update this in next patchset.


> -Kishon

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH v3 02/16] phy: qcom-qmp: Adapt to clk_bulk_* APIs

2017-12-19 Thread Manu Gautam


On 12/20/2017 8:07 AM, Vivek Gautam wrote:
> Hi Manu,
>
> [snip]
>
>> @@ -998,29 +992,17 @@ static int qcom_qmp_phy_reset_init(struct device *dev)
>>  static int qcom_qmp_phy_clk_init(struct device *dev)
>>  {
>> struct qcom_qmp *qmp = dev_get_drvdata(dev);
>> -   int ret, i;
>> +   int num = qmp->cfg->num_clks;
>> +   int i;
>>
>> -   qmp->clks = devm_kcalloc(dev, qmp->cfg->num_clks,
>> -sizeof(*qmp->clks), GFP_KERNEL);
>> +   qmp->clks = devm_kcalloc(dev, num, sizeof(*qmp->clks), GFP_KERNEL);
>> if (!qmp->clks)
>> return -ENOMEM;
>>
>> -   for (i = 0; i < qmp->cfg->num_clks; i++) {
>> -   struct clk *_clk;
>> -   const char *name = qmp->cfg->clk_list[i];
>> -
>> -   _clk = devm_clk_get(dev, name);
>> -   if (IS_ERR(_clk)) {
>> -   ret = PTR_ERR(_clk);
>> -   if (ret != -EPROBE_DEFER)
>> -   dev_err(dev, "failed to get %s clk, %d\n",
>> -   name, ret);
>> -   return ret;
>> -   }
>> -   qmp->clks[i] = _clk;
>> -   }
>> +   for (i = 0; i < num; i++)
>> +   qmp->clks->id = qmp->cfg->clk_list[i];
> I think i missed this one while rebasing.
> We need to use index with this. Should be:
> qmp->clks[i]->id = qmp->cfg->clk_list[i];
>

Thanks, I will change this accordingly in next version.


> Regards
> Vivek
>
>

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH v3 14/16] phy: Add notify_speed callback

2017-12-19 Thread Manu Gautam
Hi,


On 12/20/2017 11:19 AM, Kishon Vijay Abraham I wrote:
> Hi,
>
> On Tuesday 12 December 2017 08:54 PM, Manu Gautam wrote:
>> Hi,
>>
>>
>> On 12/12/2017 5:13 PM, Kishon Vijay Abraham I wrote:
>>> Hi,
>>>
>>> On Tuesday 21 November 2017 02:53 PM, Manu Gautam wrote:
>>>> QCOM USB PHYs can monitor resume/remote-wakeup event in
>>>> suspended state. However PHY driver must know current
>>>> operational speed of PHY in order to set correct polarity of
>>>> wakeup events for detection. E.g. QUSB2 PHY monitors DP/DM
>>>> signals depending on speed is LS or FS/HS to detect resume.
>>>> Similarly QMP USB3 PHY in SS mode should monitor RX
>>>> terminations attach/detach and LFPS events depending on
>>>> SSPHY is active or not.
> Why not use a notification mechanism instead of adding new APIs in phy-core.
> This will only bloat phy-core with APIs for a particular platform.

Do you mean notifier_chains ?
When we have multiple instances of USB PHYs then notifier chains are not
of much help. For any platform glue or PHY driver it will be very difficult to
figure out if notification received for speed was for same phy/bus or a
different one.
Using PHY callbacks looked more elegant to me. Additionally PHY drivers
can also use this info decide power management policy e.g. if speed is
INVALID then it means PHY is not in a session and it can enter deepest
low power state.
Additionally if you prefer set_speed name over notify_speed then I am
ok with that as well so that it sounds more generic.

>
> Thanks
> Kishon
>

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH v3 14/16] phy: Add notify_speed callback

2017-12-20 Thread Manu Gautam
Hi


On 12/20/2017 12:47 PM, Kishon Vijay Abraham I wrote:
> Hi,
>
[snip]
>>> Why not use a notification mechanism instead of adding new APIs in phy-core.
>>> This will only bloat phy-core with APIs for a particular platform.
>> Do you mean notifier_chains ?
>> When we have multiple instances of USB PHYs then notifier chains are not
>> of much help. For any platform glue or PHY driver it will be very difficult 
>> to
>> figure out if notification received for speed was for same phy/bus or a
>> different one.
>> Using PHY callbacks looked more elegant to me. Additionally PHY drivers
>> can also use this info decide power management policy e.g. if speed is
>> INVALID then it means PHY is not in a session and it can enter deepest
>> low power state.
>> Additionally if you prefer set_speed name over notify_speed then I am
>> ok with that as well so that it sounds more generic.
> I'd prefer adding modes in enum phy_mode according to speed and using 
> phy_set_mode.

yeah, that also seems good idea. How about something like this:

--- a/include/linux/phy/phy.h
+++ b/include/linux/phy/phy.h
@@ -23,12 +23,16 @@
 struct phy;
 
 enum phy_mode {
-   PHY_MODE_INVALID,
-   PHY_MODE_USB_HOST,
-   PHY_MODE_USB_DEVICE,
-   PHY_MODE_USB_OTG,
-   PHY_MODE_SGMII,
-   PHY_MODE_10GKR,
+   PHY_MODE_INVALID= 0,
+   PHY_MODE_USB_HOST   = BIT(0),
+   PHY_MODE_USB_DEVICE = BIT(1),
+   PHY_MODE_USB_OTG,   = BIT(2),
+   PHY_MODE_SGMII  = BIT(3),
+   PHY_MODE_10GKR  = BIT(4),
+   PHY_MODE_USB_LS = BIT(5),
+   PHY_MODE_USB_FS = BIT(6),
+   PHY_MODE_USB_HS = BIT(7),
+   PHY_MODE_USB_SS = BIT(8),
 };


This way I don't need to duplicate USB speed enums for host/device or otg modes.

> Thanks
> Kishon

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH v3 03/16] phy: qcom-qmp: Power-on PHY before initialization

2017-11-22 Thread Manu Gautam
Hi,

On 11/22/2017 11:33 PM, Stephen Boyd wrote:
> On 11/21/2017 01:23 AM, Manu Gautam wrote:
>> PHY must be powered on before turning ON clocks and
>> attempting to initialize it. Driver is exposing
>> separate init and power_on routines for this.
>> Apparently USB dwc3 core driver performs power-on after
>> init. Also, poweron and init for QMP PHY need to be
> Why does dwc3 driver power on after init? Seems backwards.

There are not many PHY drivers implementing power_on, rather they
rely on init to take care of complete initialization. However though
the name indicates power_on, but PHY drivers are not using it to
turn on power supplies but rather PHY register operations to enable/
start PHY - somewhat like init only.

>
>> executed together always, hence remove poweron callback
>> from phy_ops and explicitly perform this from com_init,
> Why do they need to be executed together?

Hardware programming guide requires PHY supplies to be ON before
it is initialized. And if PHY supplies were turned-off, then it must
be reset after turning them ON.


>
>> similar changes needed for poweroff. On similar lines move
>> clk_enable from init to com_init which can be called once
>> for multi lane PHYs.
> Please add parenthesis, clk_enable() for example, to functions so we
> know they're functions.

Ok.

>
>> Signed-off-by: Manu Gautam 
>> ---
>>  drivers/phy/qualcomm/phy-qcom-qmp.c | 61 
>> +
>>  1 file changed, 21 insertions(+), 40 deletions(-)
>>
>> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c 
>> b/drivers/phy/qualcomm/phy-qcom-qmp.c
>> index 90794dd..2f427e3 100644
>> --- a/drivers/phy/qualcomm/phy-qcom-qmp.c
>> +++ b/drivers/phy/qualcomm/phy-qcom-qmp.c
>> @@ -720,33 +720,6 @@ static void qcom_qmp_phy_configure(void __iomem *base,
>>  }
>>  }
>>  
>> -static int qcom_qmp_phy_poweron(struct phy *phy)
>> -{
>> -struct qmp_phy *qphy = phy_get_drvdata(phy);
>> -struct qcom_qmp *qmp = qphy->qmp;
>> -int num = qmp->cfg->num_vregs;
>> -int ret;
>> -
>> -dev_vdbg(&phy->dev, "Powering on QMP phy\n");
>> -
>> -/* turn on regulator supplies */
>> -ret = regulator_bulk_enable(num, qmp->vregs);
>> -if (ret)
>> -dev_err(qmp->dev, "failed to enable regulators, err=%d\n", ret);
>> -
>> -return ret;
>> -}
>> -
>> -static int qcom_qmp_phy_poweroff(struct phy *phy)
>> -{
>> -struct qmp_phy *qphy = phy_get_drvdata(phy);
>> -struct qcom_qmp *qmp = qphy->qmp;
>> -
>> -regulator_bulk_disable(qmp->cfg->num_vregs, qmp->vregs);
>> -
>> -return 0;
>> -}
>> -
>>  static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
>>  {
>>  const struct qmp_phy_cfg *cfg = qmp->cfg;
>> @@ -759,6 +732,19 @@ static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
>>  return 0;
>>  }
>>  
>> +/* turn on regulator supplies */
>> +ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs);
>> +if (ret) {
>> +mutex_unlock(&qmp->phy_mutex);
>> +return ret;
> This could also be a goto.

Yes, I can replace with goto here.

>
>> +}
>> +
>> +ret = clk_bulk_prepare_enable(cfg->num_clks, qmp->clks);
>> +if (ret) {
>> +dev_err(qmp->dev, "failed to enable clks, err=%d\n", ret);
>> +goto err_clk_enable;
>> +}
>> +
>>  for (i = 0; i < cfg->num_resets; i++) {
>>  ret = reset_control_deassert(qmp->resets[i]);
>>  if (ret) {

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH v3 10/16] phy: qcom-qmp: Move register offsets to header file

2017-11-22 Thread Manu Gautam
Hi,


On 11/22/2017 10:56 PM, Stephen Boyd wrote:
> On 11/21/2017 01:23 AM, Manu Gautam wrote:
>> New revision (v3) of QMP PHY uses different offsets
>> for almost all of the registers. Hence, move these
>> definitions to header file so that updated offsets
>> can be added for QMP v3.
>>
>> Signed-off-by: Manu Gautam 
>> ---
> Why? It would only be included into one C file so it's really not necessary.

Yes, it is not necessary but it keep QMP PHY driver clean. V3 PHY duplicates 
all the
#defines and this could continue for future revisions as well.
Please refer to this patch:
 - [PATCH v3 11/16] phy: qcom-qmp: Add register offsets for QMP V3 PHY


-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH] usb: gadget: uvc:change the UVC_NUM_REQUESTS value

2017-12-25 Thread Manu Gautam
Hi,


On 12/26/2017 8:22 AM, Lipengcheng wrote:
> The value is 4, it can cache four descriptors. When streaming_interval = 1,
> it can tolerate 500us. Some busy scenes, it may be more than 500us because
> cpu scheduling is not timely. There will have some problems. It is better
> set to eight.
>
> Signed-off-by: Pengcheng Li 
> ---
>  drivers/usb/gadget/function/uvc.h | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/usb/gadget/function/uvc.h 
> b/drivers/usb/gadget/function/uvc.h
> index a64e07e..901487e 100644
> --- a/drivers/usb/gadget/function/uvc.h
> +++ b/drivers/usb/gadget/function/uvc.h
> @@ -90,7 +90,7 @@ extern unsigned int uvc_gadget_trace_param;
>   * Driver specific constants
>   */
>
> -#define UVC_NUM_REQUESTS   4
> +#define UVC_NUM_REQUESTS   8

Can we rather make it 16?
I ran into similar issue on QCOM platform with DWC3 and with 8 requests also 
data loss
was observed. 16 requests (i.e. ~2msec) worked fine.

>  #define UVC_MAX_REQUEST_SIZE   64
>  #define UVC_MAX_EVENTS 4
>
> --
> 2.7.4
>
> N�r��y���b�X��ǧv�^�)޺{.n�+{�^n�r���z���h&���G���h�(�階�ݢj"���m�z�ޖ���f���h���~�mml==

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v4 02/16] phy: qcom-qmp: Adapt to clk_bulk_* APIs

2018-01-03 Thread Manu Gautam
From: Vivek Gautam 

Move from using array of clocks to clk_bulk_* APIs that
are available now.

Signed-off-by: Vivek Gautam 
Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qmp.c | 50 -
 1 file changed, 16 insertions(+), 34 deletions(-)

diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c 
b/drivers/phy/qualcomm/phy-qcom-qmp.c
index 2526971..5fed1ae 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.c
@@ -555,7 +555,7 @@ struct qcom_qmp {
struct device *dev;
void __iomem *serdes;
 
-   struct clk **clks;
+   struct clk_bulk_data *clks;
struct reset_control **resets;
struct regulator_bulk_data *vregs;
 
@@ -857,22 +857,19 @@ static int qcom_qmp_phy_init(struct phy *phy)
void __iomem *pcs = qphy->pcs;
void __iomem *status;
unsigned int mask, val;
-   int ret, i;
+   int ret;
 
dev_vdbg(qmp->dev, "Initializing QMP phy\n");
 
-   for (i = 0; i < qmp->cfg->num_clks; i++) {
-   ret = clk_prepare_enable(qmp->clks[i]);
-   if (ret) {
-   dev_err(qmp->dev, "failed to enable %s clk, err=%d\n",
-   qmp->cfg->clk_list[i], ret);
-   goto err_clk;
-   }
+   ret = clk_bulk_prepare_enable(cfg->num_clks, qmp->clks);
+   if (ret) {
+   dev_err(qmp->dev, "failed to enable clks, err=%d\n", ret);
+   return ret;
}
 
ret = qcom_qmp_phy_com_init(qmp);
if (ret)
-   goto err_clk;
+   goto err_com_init;
 
if (cfg->has_lane_rst) {
ret = reset_control_deassert(qphy->lane_rst);
@@ -920,9 +917,8 @@ static int qcom_qmp_phy_init(struct phy *phy)
reset_control_assert(qphy->lane_rst);
 err_lane_rst:
qcom_qmp_phy_com_exit(qmp);
-err_clk:
-   while (--i >= 0)
-   clk_disable_unprepare(qmp->clks[i]);
+err_com_init:
+   clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks);
 
return ret;
 }
@@ -932,7 +928,6 @@ static int qcom_qmp_phy_exit(struct phy *phy)
struct qmp_phy *qphy = phy_get_drvdata(phy);
struct qcom_qmp *qmp = qphy->qmp;
const struct qmp_phy_cfg *cfg = qmp->cfg;
-   int i = cfg->num_clks;
 
clk_disable_unprepare(qphy->pipe_clk);
 
@@ -950,8 +945,7 @@ static int qcom_qmp_phy_exit(struct phy *phy)
 
qcom_qmp_phy_com_exit(qmp);
 
-   while (--i >= 0)
-   clk_disable_unprepare(qmp->clks[i]);
+   clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks);
 
return 0;
 }
@@ -1000,29 +994,17 @@ static int qcom_qmp_phy_reset_init(struct device *dev)
 static int qcom_qmp_phy_clk_init(struct device *dev)
 {
struct qcom_qmp *qmp = dev_get_drvdata(dev);
-   int ret, i;
+   int num = qmp->cfg->num_clks;
+   int i;
 
-   qmp->clks = devm_kcalloc(dev, qmp->cfg->num_clks,
-sizeof(*qmp->clks), GFP_KERNEL);
+   qmp->clks = devm_kcalloc(dev, num, sizeof(*qmp->clks), GFP_KERNEL);
if (!qmp->clks)
return -ENOMEM;
 
-   for (i = 0; i < qmp->cfg->num_clks; i++) {
-   struct clk *_clk;
-   const char *name = qmp->cfg->clk_list[i];
-
-   _clk = devm_clk_get(dev, name);
-   if (IS_ERR(_clk)) {
-   ret = PTR_ERR(_clk);
-   if (ret != -EPROBE_DEFER)
-   dev_err(dev, "failed to get %s clk, %d\n",
-   name, ret);
-   return ret;
-   }
-   qmp->clks[i] = _clk;
-   }
+   for (i = 0; i < num; i++)
+   qmp->clks[i].id = qmp->cfg->clk_list[i];
 
-   return 0;
+   return devm_clk_bulk_get(dev, num, qmp->clks);
 }
 
 /*
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v4 03/16] phy: qcom-qmp: Power-on PHY before initialization

2018-01-03 Thread Manu Gautam
PHY regulators which are enabled from power_on() must be ON
before turning-on clocks and initializing it as part of init().
As most of the core drivers perform power_on() after init(), move
PHY regulators enable to com_init() and use power_on() to
only enable pipe_clk. This pipe_clk is output from PHY and some
core drivers e.g. PCIe follow specific sequence after phy_init()
that mandates pipe_clk to be enabled from power_on() only.
On similar lines move clk_enable from init() to com_init() which
executes once for multi lane PHYs.

Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qmp.c | 61 +++--
 1 file changed, 24 insertions(+), 37 deletions(-)

diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c 
b/drivers/phy/qualcomm/phy-qcom-qmp.c
index 5fed1ae..1b82cea 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.c
@@ -724,36 +724,13 @@ static int qcom_qmp_phy_poweron(struct phy *phy)
 {
struct qmp_phy *qphy = phy_get_drvdata(phy);
struct qcom_qmp *qmp = qphy->qmp;
-   int num = qmp->cfg->num_vregs;
int ret;
 
-   dev_vdbg(&phy->dev, "Powering on QMP phy\n");
-
-   /* turn on regulator supplies */
-   ret = regulator_bulk_enable(num, qmp->vregs);
-   if (ret) {
-   dev_err(qmp->dev, "failed to enable regulators, err=%d\n", ret);
-   return ret;
-   }
-
ret = clk_prepare_enable(qphy->pipe_clk);
-   if (ret) {
+   if (ret)
dev_err(qmp->dev, "pipe_clk enable failed, err=%d\n", ret);
-   regulator_bulk_disable(num, qmp->vregs);
-   return ret;
-   }
 
-   return 0;
-}
-
-static int qcom_qmp_phy_poweroff(struct phy *phy)
-{
-   struct qmp_phy *qphy = phy_get_drvdata(phy);
-   struct qcom_qmp *qmp = qphy->qmp;
-
-   regulator_bulk_disable(qmp->cfg->num_vregs, qmp->vregs);
-
-   return 0;
+   return ret;
 }
 
 static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
@@ -768,6 +745,19 @@ static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
return 0;
}
 
+   /* turn on regulator supplies */
+   ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs);
+   if (ret) {
+   dev_err(qmp->dev, "failed to enable regulators, err=%d\n", ret);
+   goto err_reg_enable;
+   }
+
+   ret = clk_bulk_prepare_enable(cfg->num_clks, qmp->clks);
+   if (ret) {
+   dev_err(qmp->dev, "failed to enable clks, err=%d\n", ret);
+   goto err_clk_enable;
+   }
+
for (i = 0; i < cfg->num_resets; i++) {
ret = reset_control_deassert(qmp->resets[i]);
if (ret) {
@@ -812,6 +802,10 @@ static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
 err_rst:
while (--i >= 0)
reset_control_assert(qmp->resets[i]);
+   clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks);
+err_clk_enable:
+   regulator_bulk_disable(cfg->num_vregs, qmp->vregs);
+err_reg_enable:
mutex_unlock(&qmp->phy_mutex);
 
return ret;
@@ -841,6 +835,10 @@ static int qcom_qmp_phy_com_exit(struct qcom_qmp *qmp)
while (--i >= 0)
reset_control_assert(qmp->resets[i]);
 
+   clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks);
+
+   regulator_bulk_disable(cfg->num_vregs, qmp->vregs);
+
mutex_unlock(&qmp->phy_mutex);
 
return 0;
@@ -861,15 +859,9 @@ static int qcom_qmp_phy_init(struct phy *phy)
 
dev_vdbg(qmp->dev, "Initializing QMP phy\n");
 
-   ret = clk_bulk_prepare_enable(cfg->num_clks, qmp->clks);
-   if (ret) {
-   dev_err(qmp->dev, "failed to enable clks, err=%d\n", ret);
-   return ret;
-   }
-
ret = qcom_qmp_phy_com_init(qmp);
if (ret)
-   goto err_com_init;
+   return ret;
 
if (cfg->has_lane_rst) {
ret = reset_control_deassert(qphy->lane_rst);
@@ -917,8 +909,6 @@ static int qcom_qmp_phy_init(struct phy *phy)
reset_control_assert(qphy->lane_rst);
 err_lane_rst:
qcom_qmp_phy_com_exit(qmp);
-err_com_init:
-   clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks);
 
return ret;
 }
@@ -945,8 +935,6 @@ static int qcom_qmp_phy_exit(struct phy *phy)
 
qcom_qmp_phy_com_exit(qmp);
 
-   clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks);
-
return 0;
 }
 
@@ -1060,7 +1048,6 @@ static int phy_pipe_clk_register(struct qcom_qmp *qmp, 
struct device_node *np)
.init   = qcom_qmp_phy_init,
.exit   = qcom_qmp_phy_exit,
.power_on   = qcom_qmp_phy_poweron,
-   .power_off  = qcom_qmp_phy_poweroff,
.owner  = THIS_MODULE,
 };
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v4 04/16] phy: qcom-qusb2: Power-on PHY before initialization

2018-01-03 Thread Manu Gautam
PHY must be powered on before turning ON clocks and
attempting to initialize it. Driver is exposing
separate init and power_on routines for this.
Apparently USB dwc3 core driver performs power-on
after init. Also, poweron and init for QUSB2 PHY
need to be executed together always, hence remove
poweron callback from phy_ops and explicitly perform
this from init, similar changes needed for poweroff.

Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qusb2.c | 47 +++
 1 file changed, 15 insertions(+), 32 deletions(-)

diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c 
b/drivers/phy/qualcomm/phy-qcom-qusb2.c
index 6c57524..4a5b2a1 100644
--- a/drivers/phy/qualcomm/phy-qcom-qusb2.c
+++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c
@@ -195,54 +195,31 @@ static void qusb2_phy_set_tune2_param(struct qusb2_phy 
*qphy)
qusb2_setbits(qphy->base, QUSB2PHY_PORT_TUNE2, val[0] << 0x4);
 }
 
-static int qusb2_phy_poweron(struct phy *phy)
+static int qusb2_phy_init(struct phy *phy)
 {
struct qusb2_phy *qphy = phy_get_drvdata(phy);
-   int num = ARRAY_SIZE(qphy->vregs);
+   unsigned int val;
+   unsigned int clk_scheme;
int ret;
 
-   dev_vdbg(&phy->dev, "%s(): Powering-on QUSB2 phy\n", __func__);
+   dev_vdbg(&phy->dev, "%s(): Initializing QUSB2 phy\n", __func__);
 
/* turn on regulator supplies */
-   ret = regulator_bulk_enable(num, qphy->vregs);
+   ret = regulator_bulk_enable(ARRAY_SIZE(qphy->vregs), qphy->vregs);
if (ret)
return ret;
 
ret = clk_prepare_enable(qphy->iface_clk);
if (ret) {
dev_err(&phy->dev, "failed to enable iface_clk, %d\n", ret);
-   regulator_bulk_disable(num, qphy->vregs);
-   return ret;
+   goto poweroff_phy;
}
 
-   return 0;
-}
-
-static int qusb2_phy_poweroff(struct phy *phy)
-{
-   struct qusb2_phy *qphy = phy_get_drvdata(phy);
-
-   clk_disable_unprepare(qphy->iface_clk);
-
-   regulator_bulk_disable(ARRAY_SIZE(qphy->vregs), qphy->vregs);
-
-   return 0;
-}
-
-static int qusb2_phy_init(struct phy *phy)
-{
-   struct qusb2_phy *qphy = phy_get_drvdata(phy);
-   unsigned int val;
-   unsigned int clk_scheme;
-   int ret;
-
-   dev_vdbg(&phy->dev, "%s(): Initializing QUSB2 phy\n", __func__);
-
/* enable ahb interface clock to program phy */
ret = clk_prepare_enable(qphy->cfg_ahb_clk);
if (ret) {
dev_err(&phy->dev, "failed to enable cfg ahb clock, %d\n", ret);
-   return ret;
+   goto disable_iface_clk;
}
 
/* Perform phy reset */
@@ -344,6 +321,11 @@ static int qusb2_phy_init(struct phy *phy)
reset_control_assert(qphy->phy_reset);
 disable_ahb_clk:
clk_disable_unprepare(qphy->cfg_ahb_clk);
+disable_iface_clk:
+   clk_disable_unprepare(qphy->iface_clk);
+poweroff_phy:
+   regulator_bulk_disable(ARRAY_SIZE(qphy->vregs), qphy->vregs);
+
return ret;
 }
 
@@ -361,6 +343,9 @@ static int qusb2_phy_exit(struct phy *phy)
reset_control_assert(qphy->phy_reset);
 
clk_disable_unprepare(qphy->cfg_ahb_clk);
+   clk_disable_unprepare(qphy->iface_clk);
+
+   regulator_bulk_disable(ARRAY_SIZE(qphy->vregs), qphy->vregs);
 
return 0;
 }
@@ -368,8 +353,6 @@ static int qusb2_phy_exit(struct phy *phy)
 static const struct phy_ops qusb2_phy_gen_ops = {
.init   = qusb2_phy_init,
.exit   = qusb2_phy_exit,
-   .power_on   = qusb2_phy_poweron,
-   .power_off  = qusb2_phy_poweroff,
.owner  = THIS_MODULE,
 };
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v4 01/16] phy: qcom-qmp: Fix phy pipe clock gating

2018-01-03 Thread Manu Gautam
From: Vivek Gautam 

Pipe clock comes out of the phy and is available as long as
the phy is turned on. Clock controller fails to gate this
clock after the phy is turned off and generates a warning.

/ # [   33.048561] gcc_usb3_phy_pipe_clk status stuck at 'on'
[   33.048585] [ cut here ]
[   33.052621] WARNING: CPU: 1 PID: 18 at ../drivers/clk/qcom/clk-branch.c:97 
clk_branch_wait+0xf0/0x108
[   33.057384] Modules linked in:
[   33.066497] CPU: 1 PID: 18 Comm: kworker/1:0 Tainted: GW   
4.12.0-rc7-00024-gfe926e34c36d-dirty #96
[   33.069451] Hardware name: Qualcomm Technologies, Inc. DB820c (DT)
...
[   33.278565] [] clk_branch_wait+0xf0/0x108
[   33.286375] [] clk_branch2_disable+0x28/0x34
[   33.291761] [] clk_core_disable+0x5c/0x88
[   33.297660] [] clk_core_disable_lock+0x20/0x34
[   33.303129] [] clk_disable+0x1c/0x24
[   33.309384] [] qcom_qmp_phy_poweroff+0x20/0x48
[   33.314328] [] phy_power_off+0x80/0xdc
[   33.320492] [] dwc3_core_exit+0x94/0xa0
[   33.325784] [] dwc3_suspend_common+0x50/0x60
[   33.331080] [] dwc3_runtime_suspend+0x48/0x6c
[   33.336810] [] pm_generic_runtime_suspend+0x28/0x38
[   33.342627] [] __rpm_callback+0x150/0x254
[   33.349222] [] rpm_callback+0x24/0x78
[   33.354604] [] rpm_suspend+0xe0/0x4e4
[   33.359813] [] pm_runtime_work+0xdc/0xf0
[   33.365028] [] process_one_work+0x12c/0x28c
[   33.370576] [] worker_thread+0x58/0x3b8
[   33.376393] [] kthread+0x100/0x12c
[   33.381776] [] ret_from_fork+0x10/0x50

Fix this by disabling it as the first thing in phy_exit().

Fixes: e78f3d15e115 ("phy: qcom-qmp: new qmp phy driver for qcom-chipsets")
Signed-off-by: Vivek Gautam 
Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qmp.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c 
b/drivers/phy/qualcomm/phy-qcom-qmp.c
index e17f035..2526971 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.c
@@ -751,8 +751,6 @@ static int qcom_qmp_phy_poweroff(struct phy *phy)
struct qmp_phy *qphy = phy_get_drvdata(phy);
struct qcom_qmp *qmp = qphy->qmp;
 
-   clk_disable_unprepare(qphy->pipe_clk);
-
regulator_bulk_disable(qmp->cfg->num_vregs, qmp->vregs);
 
return 0;
@@ -936,6 +934,8 @@ static int qcom_qmp_phy_exit(struct phy *phy)
const struct qmp_phy_cfg *cfg = qmp->cfg;
int i = cfg->num_clks;
 
+   clk_disable_unprepare(qphy->pipe_clk);
+
/* PHY reset */
qphy_setbits(qphy->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v4 07/16] phy: qcom-qusb2: Add support for different register layouts

2018-01-03 Thread Manu Gautam
New version of QUSB2 PHY has some registers offset changed.
Add support to have register layout for a target and update
the same in phy_configuration.

Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qusb2.c | 149 +-
 1 file changed, 109 insertions(+), 40 deletions(-)

diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c 
b/drivers/phy/qualcomm/phy-qcom-qusb2.c
index 4a5b2a1..b65635f 100644
--- a/drivers/phy/qualcomm/phy-qcom-qusb2.c
+++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c
@@ -37,17 +37,10 @@
 #define QUSB2PHY_PLL_AUTOPGM_CTL1  0x1c
 #define QUSB2PHY_PLL_PWR_CTRL  0x18
 
-#define QUSB2PHY_PLL_STATUS0x38
+/* QUSB2PHY_PLL_STATUS register bits */
 #define PLL_LOCKED BIT(5)
 
-#define QUSB2PHY_PORT_TUNE10x80
-#define QUSB2PHY_PORT_TUNE20x84
-#define QUSB2PHY_PORT_TUNE30x88
-#define QUSB2PHY_PORT_TUNE40x8c
-#define QUSB2PHY_PORT_TUNE50x90
-#define QUSB2PHY_PORT_TEST20x9c
-
-#define QUSB2PHY_PORT_POWERDOWN0xb4
+/* QUSB2PHY_PORT_POWERDOWN register bits */
 #define CLAMP_N_EN BIT(5)
 #define FREEZIO_N  BIT(1)
 #define POWER_DOWN BIT(0)
@@ -59,6 +52,11 @@
 struct qusb2_phy_init_tbl {
unsigned int offset;
unsigned int val;
+   /*
+* register part of layout ?
+* if yes, then offset gives index in the reg-layout
+*/
+   int in_layout;
 };
 
 #define QUSB2_PHY_INIT_CFG(o, v) \
@@ -67,15 +65,50 @@ struct qusb2_phy_init_tbl {
.val = v,   \
}
 
+#define QUSB2_PHY_INIT_CFG_L(o, v) \
+   {   \
+   .offset = o,\
+   .val = v,   \
+   .in_layout = 1, \
+   }
+
+/* set of registers with offsets different per-PHY */
+enum qusb2phy_reg_layout {
+   QUSB2PHY_PLL_STATUS,
+   QUSB2PHY_PORT_TUNE1,
+   QUSB2PHY_PORT_TUNE2,
+   QUSB2PHY_PORT_TUNE3,
+   QUSB2PHY_PORT_TUNE4,
+   QUSB2PHY_PORT_TUNE5,
+   QUSB2PHY_PORT_TEST1,
+   QUSB2PHY_PORT_TEST2,
+   QUSB2PHY_PORT_POWERDOWN,
+   QUSB2PHY_INTR_CTRL,
+};
+
+static const unsigned int msm8996_regs_layout[] = {
+   [QUSB2PHY_PLL_STATUS]   = 0x38,
+   [QUSB2PHY_PORT_TUNE1]   = 0x80,
+   [QUSB2PHY_PORT_TUNE2]   = 0x84,
+   [QUSB2PHY_PORT_TUNE3]   = 0x88,
+   [QUSB2PHY_PORT_TUNE4]   = 0x8c,
+   [QUSB2PHY_PORT_TUNE5]   = 0x90,
+   [QUSB2PHY_PORT_TEST2]   = 0x9c,
+   [QUSB2PHY_PORT_POWERDOWN]   = 0xb4,
+};
+
 static const struct qusb2_phy_init_tbl msm8996_init_tbl[] = {
-   QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TUNE1, 0xf8),
-   QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TUNE2, 0xb3),
-   QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TUNE3, 0x83),
-   QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TUNE4, 0xc0),
+   QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE1, 0xf8),
+   QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE2, 0xb3),
+   QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE3, 0x83),
+   QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE4, 0xc0),
+
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_TUNE, 0x30),
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_USER_CTL1, 0x79),
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_USER_CTL2, 0x21),
-   QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TEST2, 0x14),
+
+   QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TEST2, 0x14),
+
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_AUTOPGM_CTL1, 0x9f),
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_PWR_CTRL, 0x00),
 };
@@ -86,11 +119,27 @@ struct qusb2_phy_cfg {
unsigned int tbl_num;
/* offset to PHY_CLK_SCHEME register in TCSR map */
unsigned int clk_scheme_offset;
+
+   /* array of registers with different offsets */
+   const unsigned int *regs;
+   unsigned int mask_core_ready;
+   unsigned int disable_ctrl;
+
+   /* true if PHY has PLL_TEST register to select clk_scheme */
+   bool has_pll_test;
+
+   /* true if TUNE1 register must be updated by fused value, else TUNE2 */
+   bool update_tune1_with_efuse;
 };
 
 static const struct qusb2_phy_cfg msm8996_phy_cfg = {
-   .tbl = msm8996_init_tbl,
-   .tbl_num = ARRAY_SIZE(msm8996_init_tbl),
+   .tbl= msm8996_init_tbl,
+   .tbl_num= ARRAY_SIZE(msm8996_init_tbl),
+   .regs   = msm8996_regs_layout,
+
+   .has_pll_test   = true,
+   .disable_ctrl   = (CLAMP_N_EN | FREEZIO_N | POWER_DOWN),
+   .mask_core_ready = PLL_LOCKED,
 };
 
 static const char * const qusb2_phy_vreg_names[] = {
@@ -160,26 +209,32 @@ static inline void qusb2_clrbits(void __iomem *base, u32 
offset, u32 val)
 
 static inline
 void qcom_qusb2_phy_configure(void __iomem *base,
+ const unsigned int *regs,
  const struct qusb2_phy_init_tbl tbl[], int num)
 {
int i;
 
-   for (i = 0; i < num

[PATCH v4 06/16] phy: qcom-qmp: Move SERDES/PCS START after PHY reset

2018-01-03 Thread Manu Gautam
Driver is currently performing PHY reset after starting
SERDES/PCS. As per hardware datasheet reset must be done
before starting PHY. Hence, update the sequence.

Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qmp.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c 
b/drivers/phy/qualcomm/phy-qcom-qmp.c
index ecff261..edb6bbe 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.c
@@ -896,12 +896,12 @@ static int qcom_qmp_phy_init(struct phy *phy)
if (cfg->has_pwrdn_delay)
usleep_range(cfg->pwrdn_delay_min, cfg->pwrdn_delay_max);
 
-   /* start SerDes and Phy-Coding-Sublayer */
-   qphy_setbits(pcs, cfg->regs[QPHY_START_CTRL], cfg->start_ctrl);
-
/* Pull PHY out of reset state */
qphy_clrbits(pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
 
+   /* start SerDes and Phy-Coding-Sublayer */
+   qphy_setbits(pcs, cfg->regs[QPHY_START_CTRL], cfg->start_ctrl);
+
status = pcs + cfg->regs[QPHY_PCS_READY_STATUS];
mask = cfg->mask_pcs_ready;
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v4 09/16] phy: qcom-qusb2: Add support for QUSB2 V2 version

2018-01-03 Thread Manu Gautam
Use register layout to add additional registers present
on QUSB2 PHY V2 version for PHY initialization.
Other than new registers on V2, following two register's
offset and bit definitions are different: POWERDOWN control
and PLL_STATUS.

Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qusb2.c | 64 +++
 1 file changed, 64 insertions(+)

diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c 
b/drivers/phy/qualcomm/phy-qcom-qusb2.c
index b65635f..8d0579e 100644
--- a/drivers/phy/qualcomm/phy-qcom-qusb2.c
+++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c
@@ -40,15 +40,34 @@
 /* QUSB2PHY_PLL_STATUS register bits */
 #define PLL_LOCKED BIT(5)
 
+/* QUSB2PHY_PLL_COMMON_STATUS_ONE register bits */
+#define CORE_READY_STATUS  BIT(0)
+
 /* QUSB2PHY_PORT_POWERDOWN register bits */
 #define CLAMP_N_EN BIT(5)
 #define FREEZIO_N  BIT(1)
 #define POWER_DOWN BIT(0)
 
+/* QUSB2PHY_PWR_CTRL1 register bits */
+#define PWR_CTRL1_VREF_SUPPLY_TRIM BIT(5)
+#define PWR_CTRL1_CLAMP_N_EN   BIT(1)
+
 #define QUSB2PHY_REFCLK_ENABLE BIT(0)
 
 #define PHY_CLK_SCHEME_SEL BIT(0)
 
+#defineQUSB2PHY_PLL_ANALOG_CONTROLS_TWO0x04
+#defineQUSB2PHY_PLL_CLOCK_INVERTERS0x18c
+#defineQUSB2PHY_PLL_CMODE  0x2c
+#defineQUSB2PHY_PLL_LOCK_DELAY 0x184
+#defineQUSB2PHY_PLL_DIGITAL_TIMERS_TWO 0xb4
+#defineQUSB2PHY_PLL_BIAS_CONTROL_1 0x194
+#defineQUSB2PHY_PLL_BIAS_CONTROL_2 0x198
+#defineQUSB2PHY_PWR_CTRL2  0x214
+#defineQUSB2PHY_IMP_CTRL1  0x220
+#defineQUSB2PHY_IMP_CTRL2  0x224
+#defineQUSB2PHY_CHG_CTRL2  0x23c
+
 struct qusb2_phy_init_tbl {
unsigned int offset;
unsigned int val;
@@ -113,6 +132,38 @@ enum qusb2phy_reg_layout {
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_PWR_CTRL, 0x00),
 };
 
+static const unsigned int qusb2_v2_regs_layout[] = {
+   [QUSB2PHY_PLL_STATUS]   = 0x1a0,
+   [QUSB2PHY_PORT_TUNE1]   = 0x240,
+   [QUSB2PHY_PORT_TUNE2]   = 0x244,
+   [QUSB2PHY_PORT_TUNE3]   = 0x248,
+   [QUSB2PHY_PORT_TUNE4]   = 0x24c,
+   [QUSB2PHY_PORT_TUNE5]   = 0x250,
+   [QUSB2PHY_PORT_TEST2]   = 0x258,
+   [QUSB2PHY_PORT_POWERDOWN]   = 0x210,
+};
+
+static const struct qusb2_phy_init_tbl qusb2_v2_init_tbl[] = {
+   QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_ANALOG_CONTROLS_TWO, 0x03),
+   QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_CLOCK_INVERTERS, 0x7c),
+   QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_CMODE, 0x80),
+   QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_LOCK_DELAY, 0x0a),
+   QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_DIGITAL_TIMERS_TWO, 0x19),
+   QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_BIAS_CONTROL_1, 0x40),
+   QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_BIAS_CONTROL_2, 0x20),
+   QUSB2_PHY_INIT_CFG(QUSB2PHY_PWR_CTRL2, 0x21),
+   QUSB2_PHY_INIT_CFG(QUSB2PHY_IMP_CTRL1, 0x0),
+   QUSB2_PHY_INIT_CFG(QUSB2PHY_IMP_CTRL2, 0x58),
+
+   QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE1, 0x30),
+   QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE2, 0x29),
+   QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE3, 0xca),
+   QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE4, 0x04),
+   QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE5, 0x03),
+
+   QUSB2_PHY_INIT_CFG(QUSB2PHY_CHG_CTRL2, 0x0),
+};
+
 struct qusb2_phy_cfg {
const struct qusb2_phy_init_tbl *tbl;
/* number of entries in the table */
@@ -142,6 +193,16 @@ struct qusb2_phy_cfg {
.mask_core_ready = PLL_LOCKED,
 };
 
+static const struct qusb2_phy_cfg qusb2_v2_phy_cfg = {
+   .tbl= qusb2_v2_init_tbl,
+   .tbl_num= ARRAY_SIZE(qusb2_v2_init_tbl),
+   .regs   = qusb2_v2_regs_layout,
+
+   .disable_ctrl   = (PWR_CTRL1_VREF_SUPPLY_TRIM | PWR_CTRL1_CLAMP_N_EN |
+  POWER_DOWN),
+   .mask_core_ready = CORE_READY_STATUS,
+};
+
 static const char * const qusb2_phy_vreg_names[] = {
"vdda-pll", "vdda-phy-dpdm",
 };
@@ -429,6 +490,9 @@ static int qusb2_phy_exit(struct phy *phy)
{
.compatible = "qcom,msm8996-qusb2-phy",
.data   = &msm8996_phy_cfg,
+   }, {
+   .compatible = "qcom,qusb2-v2-phy",
+   .data   = &qusb2_v2_phy_cfg,
},
{ },
 };
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v4 08/16] dt-bindings: phy-qcom-qusb2: Update binding for QUSB2 V2 version

2018-01-03 Thread Manu Gautam
Update generic compatible string for QUSB2 V2 PHY. This will allow
all targets using QUSB2 V2 use same string.

Acked-by: Rob Herring 
Signed-off-by: Manu Gautam 
---
 Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt | 5 -
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt 
b/Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt
index aa0fcb0..42c9742 100644
--- a/Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt
+++ b/Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt
@@ -4,7 +4,10 @@ Qualcomm QUSB2 phy controller
 QUSB2 controller supports LS/FS/HS usb connectivity on Qualcomm chipsets.
 
 Required properties:
- - compatible: compatible list, contains "qcom,msm8996-qusb2-phy".
+ - compatible: compatible list, contains
+  "qcom,msm8996-qusb2-phy" for 14nm PHY on msm8996,
+  "qcom,qusb2-v2-phy" for QUSB2 V2 PHY.
+
  - reg: offset and length of the PHY register set.
  - #phy-cells: must be 0.
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v4 12/16] dt-bindings: phy-qcom-qmp: Update bindings for QMP V3 USB PHY

2018-01-03 Thread Manu Gautam
Update compatible string and clock names for QMP version V3
USB PHY.

Acked-by: Rob Herring 
Signed-off-by: Manu Gautam 
---
 Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt 
b/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt
index b6a9f2b..dcf1b8f 100644
--- a/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt
+++ b/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt
@@ -8,7 +8,8 @@ Required properties:
  - compatible: compatible list, contains:
   "qcom,ipq8074-qmp-pcie-phy" for PCIe phy on IPQ8074
   "qcom,msm8996-qmp-pcie-phy" for 14nm PCIe phy on msm8996,
-  "qcom,msm8996-qmp-usb3-phy" for 14nm USB3 phy on msm8996.
+  "qcom,msm8996-qmp-usb3-phy" for 14nm USB3 phy on msm8996,
+  "qcom,qmp-v3-usb3-phy" for USB3 QMP V3 phy.
 
  - reg: offset and length of register set for PHY's common serdes block.
 
@@ -25,10 +26,13 @@ Required properties:
  - clock-names: "cfg_ahb" for phy config clock,
"aux" for phy aux clock,
"ref" for 19.2 MHz ref clk,
+   "com_aux" for phy common block aux clock,
For "qcom,msm8996-qmp-pcie-phy" must contain:
"aux", "cfg_ahb", "ref".
For "qcom,msm8996-qmp-usb3-phy" must contain:
"aux", "cfg_ahb", "ref".
+   For "qcom,qmp-v3-usb3-phy" must contain:
+   "aux", "cfg_ahb", "ref", "com_aux".
 
  - resets: a list of phandles and reset controller specifier pairs,
   one for each entry in reset-names.
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v4 10/16] phy: qcom-qmp: Move register offsets to header file

2018-01-03 Thread Manu Gautam
New revision (v3) of QMP PHY uses different offsets
for almost all of the registers. Hence, move these
definitions to header file so that updated offsets
can be added for QMP v3.

Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qmp.c | 119 +--
 drivers/phy/qualcomm/phy-qcom-qmp.h | 137 
 2 files changed, 138 insertions(+), 118 deletions(-)
 create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp.h

diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c 
b/drivers/phy/qualcomm/phy-qcom-qmp.c
index edb6bbe..2a1117b 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.c
@@ -31,124 +31,7 @@
 
 #include 
 
-/* QMP PHY QSERDES COM registers */
-#define QSERDES_COM_BG_TIMER   0x00c
-#define QSERDES_COM_SSC_EN_CENTER  0x010
-#define QSERDES_COM_SSC_ADJ_PER1   0x014
-#define QSERDES_COM_SSC_ADJ_PER2   0x018
-#define QSERDES_COM_SSC_PER1   0x01c
-#define QSERDES_COM_SSC_PER2   0x020
-#define QSERDES_COM_SSC_STEP_SIZE1 0x024
-#define QSERDES_COM_SSC_STEP_SIZE2 0x028
-#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN0x034
-#define QSERDES_COM_CLK_ENABLE10x038
-#define QSERDES_COM_SYS_CLK_CTRL   0x03c
-#define QSERDES_COM_SYSCLK_BUF_ENABLE  0x040
-#define QSERDES_COM_PLL_IVCO   0x048
-#define QSERDES_COM_LOCK_CMP1_MODE00x04c
-#define QSERDES_COM_LOCK_CMP2_MODE00x050
-#define QSERDES_COM_LOCK_CMP3_MODE00x054
-#define QSERDES_COM_LOCK_CMP1_MODE10x058
-#define QSERDES_COM_LOCK_CMP2_MODE10x05c
-#define QSERDES_COM_LOCK_CMP3_MODE10x060
-#define QSERDES_COM_BG_TRIM0x070
-#define QSERDES_COM_CLK_EP_DIV 0x074
-#define QSERDES_COM_CP_CTRL_MODE0  0x078
-#define QSERDES_COM_CP_CTRL_MODE1  0x07c
-#define QSERDES_COM_PLL_RCTRL_MODE00x084
-#define QSERDES_COM_PLL_RCTRL_MODE10x088
-#define QSERDES_COM_PLL_CCTRL_MODE00x090
-#define QSERDES_COM_PLL_CCTRL_MODE10x094
-#define QSERDES_COM_BIAS_EN_CTRL_BY_PSM0x0a8
-#define QSERDES_COM_SYSCLK_EN_SEL  0x0ac
-#define QSERDES_COM_RESETSM_CNTRL  0x0b4
-#define QSERDES_COM_RESTRIM_CTRL   0x0bc
-#define QSERDES_COM_RESCODE_DIV_NUM0x0c4
-#define QSERDES_COM_LOCK_CMP_EN0x0c8
-#define QSERDES_COM_LOCK_CMP_CFG   0x0cc
-#define QSERDES_COM_DEC_START_MODE00x0d0
-#define QSERDES_COM_DEC_START_MODE10x0d4
-#define QSERDES_COM_DIV_FRAC_START1_MODE0  0x0dc
-#define QSERDES_COM_DIV_FRAC_START2_MODE0  0x0e0
-#define QSERDES_COM_DIV_FRAC_START3_MODE0  0x0e4
-#define QSERDES_COM_DIV_FRAC_START1_MODE1  0x0e8
-#define QSERDES_COM_DIV_FRAC_START2_MODE1  0x0ec
-#define QSERDES_COM_DIV_FRAC_START3_MODE1  0x0f0
-#define QSERDES_COM_INTEGLOOP_GAIN0_MODE0  0x108
-#define QSERDES_COM_INTEGLOOP_GAIN1_MODE0  0x10c
-#define QSERDES_COM_INTEGLOOP_GAIN0_MODE1  0x110
-#define QSERDES_COM_INTEGLOOP_GAIN1_MODE1  0x114
-#define QSERDES_COM_VCO_TUNE_CTRL  0x124
-#define QSERDES_COM_VCO_TUNE_MAP   0x128
-#define QSERDES_COM_VCO_TUNE1_MODE00x12c
-#define QSERDES_COM_VCO_TUNE2_MODE00x130
-#define QSERDES_COM_VCO_TUNE1_MODE10x134
-#define QSERDES_COM_VCO_TUNE2_MODE10x138
-#define QSERDES_COM_VCO_TUNE_TIMER10x144
-#define QSERDES_COM_VCO_TUNE_TIMER20x148
-#define QSERDES_COM_BG_CTRL0x170
-#define QSERDES_COM_CLK_SELECT 0x174
-#define QSERDES_COM_HSCLK_SEL  0x178
-#define QSERDES_COM_CORECLK_DIV0x184
-#define QSERDES_COM_CORE_CLK_EN0x18c
-#define QSERDES_COM_C_READY_STATUS 0x190
-#define QSERDES_COM_CMN_CONFIG 0x194
-#define QSERDES_COM_SVS_MODE_CLK_SEL   0x19c
-#define QSERDES_COM_DEBUG_BUS0 0x1a0
-#define QSERDES_COM_DEBUG_BUS1 0x1a4
-#define QSERDES_COM_DEBUG_BUS2 0x1a8
-#define QSERDES_COM_DEBUG_BUS3 0x1ac
-#define QSERDES_COM_DEBUG_BUS_SEL  0x1b0
-#define QSERDES_COM_CORECLK_DIV_MODE1

[PATCH v4 13/16] phy: qcom-qmp: Add support for QMP V3 USB3 PHY

2018-01-03 Thread Manu Gautam
QMP V3 USB3 PHY is a DisplayPort (DP) and USB combo PHY
with dual RX/TX lanes to support type-c. There is a
separate block DP_COM for configuration related to type-c
or DP. Add support for dp_com region and secondary rx/tx
lanes initialization.

Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qmp.c | 223 +++-
 1 file changed, 220 insertions(+), 3 deletions(-)

diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c 
b/drivers/phy/qualcomm/phy-qcom-qmp.c
index 2a1117b..55b8397 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.c
@@ -47,6 +47,21 @@
 /* QPHY_COM_PCS_READY_STATUS bit */
 #define PCS_READY  BIT(0)
 
+/* QPHY_V3_DP_COM_RESET_OVRD_CTRL register bits */
+/* DP PHY soft reset */
+#define SW_DPPHY_RESET BIT(0)
+/* mux to select DP PHY reset control, 0:HW control, 1: software reset */
+#define SW_DPPHY_RESET_MUX BIT(1)
+/* USB3 PHY soft reset */
+#define SW_USB3PHY_RESET   BIT(2)
+/* mux to select USB3 PHY reset control, 0:HW control, 1: software reset */
+#define SW_USB3PHY_RESET_MUX   BIT(3)
+
+/* QPHY_V3_DP_COM_PHY_MODE_CTRL register bits */
+#define USB3_MODE  BIT(0) /* enables USB3 mode */
+#define DP_MODEBIT(1) /* enables DP 
mode */
+
+
 #define PHY_INIT_COMPLETE_TIMEOUT  1000
 #define POWER_DOWN_DELAY_US_MIN10
 #define POWER_DOWN_DELAY_US_MAX11
@@ -122,6 +137,12 @@ enum qphy_reg_layout {
[QPHY_PCS_READY_STATUS] = 0x17c,
 };
 
+static const unsigned int qmp_v3_usb3phy_regs_layout[] = {
+   [QPHY_SW_RESET] = 0x00,
+   [QPHY_START_CTRL]   = 0x08,
+   [QPHY_PCS_READY_STATUS] = 0x174,
+};
+
 static const struct qmp_phy_init_tbl msm8996_pcie_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x1c),
QMP_PHY_INIT_CFG(QSERDES_COM_CLK_ENABLE1, 0x10),
@@ -350,6 +371,112 @@ enum qphy_reg_layout {
QMP_PHY_INIT_CFG_L(QPHY_START_CTRL, 0x3),
 };
 
+static const struct qmp_phy_init_tbl qmp_v3_usb3_serdes_tbl[] = {
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_IVCO, 0x07),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_EN_SEL, 0x14),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x08),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x30),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYS_CLK_CTRL, 0x02),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_RESETSM_CNTRL2, 0x08),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_CONFIG, 0x16),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_SVS_MODE_CLK_SEL, 0x01),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_HSCLK_SEL, 0x80),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_DEC_START_MODE0, 0x82),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START1_MODE0, 0xab),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START2_MODE0, 0xea),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START3_MODE0, 0x02),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_CP_CTRL_MODE0, 0x06),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_RCTRL_MODE0, 0x16),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_CCTRL_MODE0, 0x36),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE0, 0x00),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE0, 0x3f),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE2_MODE0, 0x01),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE1_MODE0, 0xc9),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORECLK_DIV_MODE0, 0x0a),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP3_MODE0, 0x00),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP2_MODE0, 0x34),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP1_MODE0, 0x15),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_EN, 0x04),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORE_CLK_EN, 0x00),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_CFG, 0x00),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_MAP, 0x00),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_BUF_ENABLE, 0x0a),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_EN_CENTER, 0x01),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER1, 0x31),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER2, 0x01),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER1, 0x00),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER2, 0x00),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE1, 0x85),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE2, 0x07),
+};
+
+static const struct qmp_phy_init_tbl qmp_v3_usb3_tx_tbl[] = {
+   QMP_PHY_INIT_CFG(QSERDES_V3_TX_HIGHZ_DRVR_EN, 0x10),
+   QMP_PHY_INIT_CFG(QSERDES_V3_TX_RCV_DETECT_LVL_2, 0x12),
+   QMP_PHY_INIT_CFG(QSERDES_V3_TX_LANE_MODE_1, 0x16),
+   QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_RX, 0x09),
+   QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX, 0x06),
+};
+
+static const struct qmp_phy_init_tbl qmp_v3_usb3_rx_tbl

[PATCH v4 11/16] phy: qcom-qmp: Add register offsets for QMP V3 PHY

2018-01-03 Thread Manu Gautam
Registers offsets for QMP V3 PHY are changed from
previous versions (1/2), update same in header file.

Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qmp.h | 149 
 1 file changed, 149 insertions(+)

diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.h 
b/drivers/phy/qualcomm/phy-qcom-qmp.h
index d930ca7..f7d4c2a 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.h
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.h
@@ -134,4 +134,153 @@
 #define QPHY_L1SS_WAKEUP_DLY_TIME_AUXCLK_LSB   0x1DC
 #define QPHY_L1SS_WAKEUP_DLY_TIME_AUXCLK_MSB   0x1E0
 
+/* Only for QMP V3 PHY - DP COM registers */
+#define QPHY_V3_DP_COM_PHY_MODE_CTRL   0x00
+#define QPHY_V3_DP_COM_SW_RESET0x04
+#define QPHY_V3_DP_COM_POWER_DOWN_CTRL 0x08
+#define QPHY_V3_DP_COM_SWI_CTRL0x0c
+#define QPHY_V3_DP_COM_TYPEC_CTRL  0x10
+#define QPHY_V3_DP_COM_TYPEC_PWRDN_CTRL0x14
+#define QPHY_V3_DP_COM_RESET_OVRD_CTRL 0x1c
+
+/* Only for QMP V3 PHY - QSERDES COM registers */
+#define QSERDES_V3_COM_BG_TIMER0x00c
+#define QSERDES_V3_COM_SSC_EN_CENTER   0x010
+#define QSERDES_V3_COM_SSC_ADJ_PER10x014
+#define QSERDES_V3_COM_SSC_ADJ_PER20x018
+#define QSERDES_V3_COM_SSC_PER10x01c
+#define QSERDES_V3_COM_SSC_PER20x020
+#define QSERDES_V3_COM_SSC_STEP_SIZE1  0x024
+#define QSERDES_V3_COM_SSC_STEP_SIZE2  0x028
+#define QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN 0x034
+#define QSERDES_V3_COM_CLK_ENABLE1 0x038
+#define QSERDES_V3_COM_SYS_CLK_CTRL0x03c
+#define QSERDES_V3_COM_SYSCLK_BUF_ENABLE   0x040
+#define QSERDES_V3_COM_PLL_IVCO0x048
+#define QSERDES_V3_COM_LOCK_CMP1_MODE0 0x098
+#define QSERDES_V3_COM_LOCK_CMP2_MODE0 0x09c
+#define QSERDES_V3_COM_LOCK_CMP3_MODE0 0x0a0
+#define QSERDES_V3_COM_LOCK_CMP1_MODE1 0x0a4
+#define QSERDES_V3_COM_LOCK_CMP2_MODE1 0x0a8
+#define QSERDES_V3_COM_LOCK_CMP3_MODE1 0x0ac
+#define QSERDES_V3_COM_CLK_EP_DIV  0x05c
+#define QSERDES_V3_COM_CP_CTRL_MODE0   0x060
+#define QSERDES_V3_COM_CP_CTRL_MODE1   0x064
+#define QSERDES_V3_COM_PLL_RCTRL_MODE0 0x068
+#define QSERDES_V3_COM_PLL_RCTRL_MODE1 0x06c
+#define QSERDES_V3_COM_PLL_CCTRL_MODE0 0x070
+#define QSERDES_V3_COM_PLL_CCTRL_MODE1 0x074
+#define QSERDES_V3_COM_SYSCLK_EN_SEL   0x080
+#define QSERDES_V3_COM_RESETSM_CNTRL   0x088
+#define QSERDES_V3_COM_RESETSM_CNTRL2  0x08c
+#define QSERDES_V3_COM_LOCK_CMP_EN 0x090
+#define QSERDES_V3_COM_LOCK_CMP_CFG0x094
+#define QSERDES_V3_COM_DEC_START_MODE0 0x0b0
+#define QSERDES_V3_COM_DEC_START_MODE1 0x0b4
+#define QSERDES_V3_COM_DIV_FRAC_START1_MODE0   0x0b8
+#define QSERDES_V3_COM_DIV_FRAC_START2_MODE0   0x0bc
+#define QSERDES_V3_COM_DIV_FRAC_START3_MODE0   0x0c0
+#define QSERDES_V3_COM_DIV_FRAC_START1_MODE1   0x0c4
+#define QSERDES_V3_COM_DIV_FRAC_START2_MODE1   0x0c8
+#define QSERDES_V3_COM_DIV_FRAC_START3_MODE1   0x0cc
+#define QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE0   0x0d8
+#define QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE0   0x0dc
+#define QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE1   0x0e0
+#define QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE1   0x0e4
+#define QSERDES_V3_COM_VCO_TUNE_CTRL   0x0ec
+#define QSERDES_V3_COM_VCO_TUNE_MAP0x0f0
+#define QSERDES_V3_COM_VCO_TUNE1_MODE0 0x0f4
+#define QSERDES_V3_COM_VCO_TUNE2_MODE0 0x0f8
+#define QSERDES_V3_COM_VCO_TUNE1_MODE1 0x0fc
+#define QSERDES_V3_COM_VCO_TUNE2_MODE1 0x100
+#define QSERDES_V3_COM_VCO_TUNE_TIMER1 0x11c
+#define QSERDES_V3_COM_VCO_TUNE_TIMER2 0x120
+#define QSERDES_V3_COM_CLK_SELECT  0x138
+#define QSERDES_V3_COM_HSCLK_SEL   0x13c
+#define QSERDES_V3_COM_CORECLK_DIV_MODE0   0x148
+#define QSERDES_V3_COM_CORECLK_DIV_MODE1   0x14c
+#define QSERDES_V3_COM_CORE_CLK_EN 0x154
+#define QSERDES_V3_COM_C_READY_STATUS  0x158
+#define QSERDES_V3_COM_CMN_CONFIG  0x15c
+#define QSERDES_V3_COM_SVS_MODE_CLK_SEL0x164
+#define QSERDES_V3_COM_DEBUG_BUS0  0x168
+#define QSERDES_V3_COM_DEBUG_BUS1  0x16c
+#define

[PATCH v4 15/16] phy: qcom-qusb2: Add support for runtime PM

2018-01-03 Thread Manu Gautam
Disable clocks and enable DP/DM wakeup interrupts when
suspending PHY.
Core driver should notify speed to PHY driver to enable
appropriate DP/DM wakeup interrupts polarity in suspend state.

Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qusb2.c | 184 ++
 1 file changed, 184 insertions(+)

diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c 
b/drivers/phy/qualcomm/phy-qcom-qusb2.c
index 8d0579e..3a9e4bd 100644
--- a/drivers/phy/qualcomm/phy-qcom-qusb2.c
+++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c
@@ -56,6 +56,18 @@
 
 #define PHY_CLK_SCHEME_SEL BIT(0)
 
+/* QUSB2PHY_INTR_CTRL register bits */
+#define DMSE_INTR_HIGH_SEL BIT(4)
+#define DPSE_INTR_HIGH_SEL BIT(3)
+#define CHG_DET_INTR_ENBIT(2)
+#define DMSE_INTR_EN   BIT(1)
+#define DPSE_INTR_EN   BIT(0)
+
+/* QUSB2PHY_PLL_CORE_INPUT_OVERRIDE register bits */
+#define CORE_PLL_EN_FROM_RESET BIT(4)
+#define CORE_RESET BIT(5)
+#define CORE_RESET_MUX BIT(6)
+
 #defineQUSB2PHY_PLL_ANALOG_CONTROLS_TWO0x04
 #defineQUSB2PHY_PLL_CLOCK_INVERTERS0x18c
 #defineQUSB2PHY_PLL_CMODE  0x2c
@@ -93,6 +105,7 @@ struct qusb2_phy_init_tbl {
 
 /* set of registers with offsets different per-PHY */
 enum qusb2phy_reg_layout {
+   QUSB2PHY_PLL_CORE_INPUT_OVERRIDE,
QUSB2PHY_PLL_STATUS,
QUSB2PHY_PORT_TUNE1,
QUSB2PHY_PORT_TUNE2,
@@ -112,8 +125,10 @@ enum qusb2phy_reg_layout {
[QUSB2PHY_PORT_TUNE3]   = 0x88,
[QUSB2PHY_PORT_TUNE4]   = 0x8c,
[QUSB2PHY_PORT_TUNE5]   = 0x90,
+   [QUSB2PHY_PORT_TEST1]   = 0xb8,
[QUSB2PHY_PORT_TEST2]   = 0x9c,
[QUSB2PHY_PORT_POWERDOWN]   = 0xb4,
+   [QUSB2PHY_INTR_CTRL]= 0xbc,
 };
 
 static const struct qusb2_phy_init_tbl msm8996_init_tbl[] = {
@@ -133,14 +148,17 @@ enum qusb2phy_reg_layout {
 };
 
 static const unsigned int qusb2_v2_regs_layout[] = {
+   [QUSB2PHY_PLL_CORE_INPUT_OVERRIDE] = 0xa8,
[QUSB2PHY_PLL_STATUS]   = 0x1a0,
[QUSB2PHY_PORT_TUNE1]   = 0x240,
[QUSB2PHY_PORT_TUNE2]   = 0x244,
[QUSB2PHY_PORT_TUNE3]   = 0x248,
[QUSB2PHY_PORT_TUNE4]   = 0x24c,
[QUSB2PHY_PORT_TUNE5]   = 0x250,
+   [QUSB2PHY_PORT_TEST1]   = 0x254,
[QUSB2PHY_PORT_TEST2]   = 0x258,
[QUSB2PHY_PORT_POWERDOWN]   = 0x210,
+   [QUSB2PHY_INTR_CTRL]= 0x230,
 };
 
 static const struct qusb2_phy_init_tbl qusb2_v2_init_tbl[] = {
@@ -175,12 +193,16 @@ struct qusb2_phy_cfg {
const unsigned int *regs;
unsigned int mask_core_ready;
unsigned int disable_ctrl;
+   unsigned int autoresume_en;
 
/* true if PHY has PLL_TEST register to select clk_scheme */
bool has_pll_test;
 
/* true if TUNE1 register must be updated by fused value, else TUNE2 */
bool update_tune1_with_efuse;
+
+   /* true if PHY has PLL_CORE_INPUT_OVERRIDE register to reset PLL */
+   bool has_pll_override;
 };
 
 static const struct qusb2_phy_cfg msm8996_phy_cfg = {
@@ -191,6 +213,7 @@ struct qusb2_phy_cfg {
.has_pll_test   = true,
.disable_ctrl   = (CLAMP_N_EN | FREEZIO_N | POWER_DOWN),
.mask_core_ready = PLL_LOCKED,
+   .autoresume_en   = BIT(3),
 };
 
 static const struct qusb2_phy_cfg qusb2_v2_phy_cfg = {
@@ -201,6 +224,8 @@ struct qusb2_phy_cfg {
.disable_ctrl   = (PWR_CTRL1_VREF_SUPPLY_TRIM | PWR_CTRL1_CLAMP_N_EN |
   POWER_DOWN),
.mask_core_ready = CORE_READY_STATUS,
+   .has_pll_override = true,
+   .autoresume_en= BIT(0),
 };
 
 static const char * const qusb2_phy_vreg_names[] = {
@@ -226,6 +251,8 @@ struct qusb2_phy_cfg {
  *
  * @cfg: phy config data
  * @has_se_clk_scheme: indicate if PHY has single-ended ref clock scheme
+ * @phy_initialized: indicate if PHY has been initialized
+ * @mode: current PHY mode
  */
 struct qusb2_phy {
struct phy *phy;
@@ -242,6 +269,8 @@ struct qusb2_phy {
 
const struct qusb2_phy_cfg *cfg;
bool has_se_clk_scheme;
+   bool phy_initialized;
+   enum phy_mode mode;
 };
 
 static inline void qusb2_setbits(void __iomem *base, u32 offset, u32 val)
@@ -317,6 +346,140 @@ static void qusb2_phy_set_tune2_param(struct qusb2_phy 
*qphy)
 
 }
 
+static int qusb2_phy_set_mode(struct phy *phy, enum phy_mode mode)
+{
+   struct qusb2_phy *qphy = phy_get_drvdata(phy);
+
+   qphy->mode = mode;
+
+   return 0;
+}
+
+static enum phy_mode qusb2_phy_get_mode(struct phy *phy)
+{
+   struct qusb2_phy *qphy = phy_get_drvdata(phy);
+
+   return qphy->mode;
+}
+
+static int __maybe_unused qusb2_phy_runtime_suspend(struct 

[PATCH v4 16/16] phy: qcom-qmp: Add support for runtime PM

2018-01-03 Thread Manu Gautam
Disable clocks and enable PHY autonomous mode to detect
wakeup events when PHY is suspended.
Core driver should notify speed to PHY driver to enable
LFPS and/or RX_DET interrupts.

Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qmp.c | 186 +++-
 drivers/phy/qualcomm/phy-qcom-qmp.h |   3 +
 2 files changed, 188 insertions(+), 1 deletion(-)

diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c 
b/drivers/phy/qualcomm/phy-qcom-qmp.c
index 55b8397..ad3251b 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.c
@@ -61,6 +61,19 @@
 #define USB3_MODE  BIT(0) /* enables USB3 mode */
 #define DP_MODEBIT(1) /* enables DP 
mode */
 
+/* QPHY_PCS_AUTONOMOUS_MODE_CTRL register bits */
+#define ARCVR_DTCT_EN  BIT(0)
+#define ALFPS_DTCT_EN  BIT(1)
+#define ARCVR_DTCT_EVENT_SEL   BIT(4)
+
+/* QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR register bits */
+#define IRQ_CLEAR  BIT(0)
+
+/* QPHY_PCS_LFPS_RXTERM_IRQ_STATUS register bits */
+#define RCVR_DETECTBIT(0)
+
+/* QPHY_V3_PCS_MISC_CLAMP_ENABLE register bits */
+#define CLAMP_EN   BIT(0) /* enables i/o clamp_n */
 
 #define PHY_INIT_COMPLETE_TIMEOUT  1000
 #define POWER_DOWN_DELAY_US_MIN10
@@ -108,6 +121,9 @@ enum qphy_reg_layout {
QPHY_SW_RESET,
QPHY_START_CTRL,
QPHY_PCS_READY_STATUS,
+   QPHY_PCS_AUTONOMOUS_MODE_CTRL,
+   QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR,
+   QPHY_PCS_LFPS_RXTERM_IRQ_STATUS,
 };
 
 static const unsigned int pciephy_regs_layout[] = {
@@ -135,12 +151,18 @@ enum qphy_reg_layout {
[QPHY_SW_RESET] = 0x00,
[QPHY_START_CTRL]   = 0x08,
[QPHY_PCS_READY_STATUS] = 0x17c,
+   [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = 0x0d4,
+   [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR]  = 0x0d8,
+   [QPHY_PCS_LFPS_RXTERM_IRQ_STATUS] = 0x178,
 };
 
 static const unsigned int qmp_v3_usb3phy_regs_layout[] = {
[QPHY_SW_RESET] = 0x00,
[QPHY_START_CTRL]   = 0x08,
[QPHY_PCS_READY_STATUS] = 0x174,
+   [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = 0x0d8,
+   [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR]  = 0x0dc,
+   [QPHY_PCS_LFPS_RXTERM_IRQ_STATUS] = 0x170,
 };
 
 static const struct qmp_phy_init_tbl msm8996_pcie_serdes_tbl[] = {
@@ -536,6 +558,7 @@ struct qmp_phy_cfg {
  * @tx: iomapped memory space for lane's tx
  * @rx: iomapped memory space for lane's rx
  * @pcs: iomapped memory space for lane's pcs
+ * @pcs_misc: iomapped memory space for lane's pcs_misc
  * @pipe_clk: pipe lock
  * @index: lane index
  * @qmp: QMP phy to which this lane belongs
@@ -546,6 +569,7 @@ struct qmp_phy {
void __iomem *tx;
void __iomem *rx;
void __iomem *pcs;
+   void __iomem *pcs_misc;
struct clk *pipe_clk;
unsigned int index;
struct qcom_qmp *qmp;
@@ -567,6 +591,8 @@ struct qmp_phy {
  * @phys: array of per-lane phy descriptors
  * @phy_mutex: mutex lock for PHY common block initialization
  * @init_count: phy common block initialization count
+ * @phy_initialized: indicate if PHY has been initialized
+ * @mode: current PHY mode
  */
 struct qcom_qmp {
struct device *dev;
@@ -582,6 +608,8 @@ struct qcom_qmp {
 
struct mutex phy_mutex;
int init_count;
+   bool phy_initialized;
+   enum phy_mode mode;
 };
 
 static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val)
@@ -995,6 +1023,7 @@ static int qcom_qmp_phy_init(struct phy *phy)
dev_err(qmp->dev, "phy initialization timed-out\n");
goto err_pcs_ready;
}
+   qmp->phy_initialized = true;
 
return ret;
 
@@ -1029,6 +1058,136 @@ static int qcom_qmp_phy_exit(struct phy *phy)
 
qcom_qmp_phy_com_exit(qmp);
 
+   qmp->phy_initialized = false;
+
+   return 0;
+}
+
+static int qcom_qmp_phy_set_mode(struct phy *phy, enum phy_mode mode)
+{
+   struct qmp_phy *qphy = phy_get_drvdata(phy);
+   struct qcom_qmp *qmp = qphy->qmp;
+
+   qmp->mode = mode;
+
+   return 0;
+}
+
+static enum phy_mode qcom_qmp_phy_get_mode(struct phy *phy)
+{
+   struct qmp_phy *qphy = phy_get_drvdata(phy);
+   struct qcom_qmp *qmp = qphy->qmp;
+
+   return qmp->mode;
+}
+
+static void qcom_qmp_phy_enable_autonomous_mode(struct qmp_phy *qphy)
+{
+   struct qcom_qmp *qmp = qphy->qmp;
+   const struct qmp_phy_cfg *cfg = qmp->cfg;
+   void __iomem *pcs = qphy->pcs;
+   void __iomem *pcs_misc = qphy->pcs_misc;
+   u32 intr_mask;
+
+   if (qmp->mode == PHY_MODE_USB_HOST_SS ||
+   qmp->mode == PHY_MODE_USB_DEVICE_SS)
+   intr_mask = ARCVR_DTCT_EN | 

[PATCH v4 14/16] phy: Add USB speed related PHY modes

2018-01-03 Thread Manu Gautam
Add following USB speed related PHY modes:
LS (Low Speed), FS (Full Speed), HS (High Speed), SS (Super Speed)

Speed related information is required by some QCOM PHY drivers
to program PHY monitor resume/remote-wakeup events in suspended
state. Speed is needed in order to set correct polarity of wakeup
events for detection. E.g. QUSB2 PHY monitors DP/DM line state
depending on whether speed is LS or FS/HS to detect resume.
Similarly QMP USB3 PHY in SS mode should monitor RX terminations
attach/detach and LFPS events depending on SSPHY is active or not.

Signed-off-by: Manu Gautam 
---
 drivers/phy/phy-core.c  | 15 +++
 include/linux/phy/phy.h | 32 
 2 files changed, 39 insertions(+), 8 deletions(-)

diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
index b4964b0..e4f0525 100644
--- a/drivers/phy/phy-core.c
+++ b/drivers/phy/phy-core.c
@@ -357,6 +357,21 @@ int phy_set_mode(struct phy *phy, enum phy_mode mode)
 }
 EXPORT_SYMBOL_GPL(phy_set_mode);
 
+enum phy_mode phy_get_mode(struct phy *phy)
+{
+   enum phy_mode ret;
+
+   if (!phy || !phy->ops->get_mode)
+   return PHY_MODE_INVALID;
+
+   mutex_lock(&phy->mutex);
+   ret = phy->ops->get_mode(phy);
+   mutex_unlock(&phy->mutex);
+
+   return ret;
+}
+EXPORT_SYMBOL_GPL(phy_get_mode);
+
 int phy_reset(struct phy *phy)
 {
int ret;
diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h
index d8da3e5..4a5cbd0 100644
--- a/include/linux/phy/phy.h
+++ b/include/linux/phy/phy.h
@@ -25,7 +25,15 @@
 enum phy_mode {
PHY_MODE_INVALID,
PHY_MODE_USB_HOST,
+   PHY_MODE_USB_HOST_LS,
+   PHY_MODE_USB_HOST_FS,
+   PHY_MODE_USB_HOST_HS,
+   PHY_MODE_USB_HOST_SS,
PHY_MODE_USB_DEVICE,
+   PHY_MODE_USB_DEVICE_LS,
+   PHY_MODE_USB_DEVICE_FS,
+   PHY_MODE_USB_DEVICE_HS,
+   PHY_MODE_USB_DEVICE_SS,
PHY_MODE_USB_OTG,
PHY_MODE_SGMII,
PHY_MODE_10GKR,
@@ -40,19 +48,21 @@ enum phy_mode {
  * @power_on: powering on the phy
  * @power_off: powering off the phy
  * @set_mode: set the mode of the phy
+ * @get_mode: get current mode of PHY
  * @reset: resetting the phy
  * @calibrate: calibrate the phy
  * @owner: the module owner containing the ops
  */
 struct phy_ops {
-   int (*init)(struct phy *phy);
-   int (*exit)(struct phy *phy);
-   int (*power_on)(struct phy *phy);
-   int (*power_off)(struct phy *phy);
-   int (*set_mode)(struct phy *phy, enum phy_mode mode);
-   int (*reset)(struct phy *phy);
-   int (*calibrate)(struct phy *phy);
-   struct module *owner;
+   int (*init)(struct phy *phy);
+   int (*exit)(struct phy *phy);
+   int (*power_on)(struct phy *phy);
+   int (*power_off)(struct phy *phy);
+   int (*set_mode)(struct phy *phy, enum phy_mode mode);
+   enum phy_mode   (*get_mode)(struct phy *phy);
+   int (*reset)(struct phy *phy);
+   int (*calibrate)(struct phy *phy);
+   struct module   *owner;
 };
 
 /**
@@ -144,6 +154,7 @@ static inline void *phy_get_drvdata(struct phy *phy)
 int phy_power_on(struct phy *phy);
 int phy_power_off(struct phy *phy);
 int phy_set_mode(struct phy *phy, enum phy_mode mode);
+enum phy_mode phy_get_mode(struct phy *phy);
 int phy_reset(struct phy *phy);
 int phy_calibrate(struct phy *phy);
 static inline int phy_get_bus_width(struct phy *phy)
@@ -260,6 +271,11 @@ static inline int phy_set_mode(struct phy *phy, enum 
phy_mode mode)
return -ENOSYS;
 }
 
+static inline enum phy_mode phy_get_mode(struct phy *phy)
+{
+   return PHY_MODE_INVALID;
+}
+
 static inline int phy_reset(struct phy *phy)
 {
if (!phy)
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v4 05/16] phy: qcom-qmp: Fix PHY block reset sequence

2018-01-03 Thread Manu Gautam
PHY block or asynchronous reset requires signal
to be asserted before de-asserting. Driver is only
de-asserting signal which is already low, hence
reset operation is a no-op. Fix this by asserting
signal first. Also, resetting requires PHY clocks
to be turned ON only after reset is finished. Fix
that as well.

Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qmp.c | 28 +++-
 1 file changed, 19 insertions(+), 9 deletions(-)

diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c 
b/drivers/phy/qualcomm/phy-qcom-qmp.c
index 1b82cea..ecff261 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.c
@@ -752,13 +752,16 @@ static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
goto err_reg_enable;
}
 
-   ret = clk_bulk_prepare_enable(cfg->num_clks, qmp->clks);
-   if (ret) {
-   dev_err(qmp->dev, "failed to enable clks, err=%d\n", ret);
-   goto err_clk_enable;
+   for (i = 0; i < cfg->num_resets; i++) {
+   ret = reset_control_assert(qmp->resets[i]);
+   if (ret) {
+   dev_err(qmp->dev, "%s reset assert failed\n",
+   cfg->reset_list[i]);
+   goto err_rst_assert;
+   }
}
 
-   for (i = 0; i < cfg->num_resets; i++) {
+   for (i = cfg->num_resets - 1; i >= 0; i--) {
ret = reset_control_deassert(qmp->resets[i]);
if (ret) {
dev_err(qmp->dev, "%s reset deassert failed\n",
@@ -767,6 +770,12 @@ static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
}
}
 
+   ret = clk_bulk_prepare_enable(cfg->num_clks, qmp->clks);
+   if (ret) {
+   dev_err(qmp->dev, "failed to enable clks, err=%d\n", ret);
+   goto err_rst;
+   }
+
if (cfg->has_phy_com_ctrl)
qphy_setbits(serdes, cfg->regs[QPHY_COM_POWER_DOWN_CONTROL],
 SW_PWRDN);
@@ -791,7 +800,7 @@ static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
if (ret) {
dev_err(qmp->dev,
"phy common block init timed-out\n");
-   goto err_rst;
+   goto err_com_init;
}
}
 
@@ -799,11 +808,12 @@ static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
 
return 0;
 
+err_com_init:
+   clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks);
 err_rst:
-   while (--i >= 0)
+   while (++i < cfg->num_resets)
reset_control_assert(qmp->resets[i]);
-   clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks);
-err_clk_enable:
+err_rst_assert:
regulator_bulk_disable(cfg->num_vregs, qmp->vregs);
 err_reg_enable:
mutex_unlock(&qmp->phy_mutex);
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH v3 07/16] phy: qcom-qusb2: Add support for different register layouts

2017-12-12 Thread Manu Gautam
Hi Vivek,


On 12/5/2017 3:53 PM, Vivek Gautam wrote:
>
>
> On 11/21/2017 02:53 PM, Manu Gautam wrote:
>> New version of QUSB2 PHY has some registers offset changed.
>> Add support to have register layout for a target and update
>> the same in phy_configuration.
>>
>> Signed-off-by: Manu Gautam 
>> ---
>>   drivers/phy/qualcomm/phy-qcom-qusb2.c | 131 
>> --
>>   1 file changed, 95 insertions(+), 36 deletions(-)
>>
>> diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c 
>> b/drivers/phy/qualcomm/phy-qcom-qusb2.c
>> index 4a5b2a1..c0c5358 100644
>> --- a/drivers/phy/qualcomm/phy-qcom-qusb2.c
>> +++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c
> [snip]
>>   /*
>> @@ -198,7 +249,8 @@ static void qusb2_phy_set_tune2_param(struct qusb2_phy 
>> *qphy)
>
> We need to add following change to qusb2_phy_set_tune2_param()
> since we have register layout now.
>
> @@ -333,7 +334,7 @@ static void qusb2_phy_set_tune2_param(struct qusb2_phy 
> *qphy)
>     }
>
>     /* Fused TUNE2 value is the higher nibble only */
> -   qusb2_setbits(qphy->base, QUSB2PHY_PORT_TUNE2, val[0] << 0x4);
> +   qusb2_setbits(qphy->base, cfg->regs[QUSB2PHY_PORT_TUNE2], val[0] << 
> 0x4);

Thanks for catching this. Actually on qusb-v2 PHY, fused value is used to update
TUNE1 instead of TUNE2 register. I will make changes accordingly.

>  }
>
> regards
> Vivek
>

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH v3 14/16] phy: Add notify_speed callback

2017-12-12 Thread Manu Gautam
Hi,


On 12/12/2017 5:13 PM, Kishon Vijay Abraham I wrote:
> Hi,
>
> On Tuesday 21 November 2017 02:53 PM, Manu Gautam wrote:
>> QCOM USB PHYs can monitor resume/remote-wakeup event in
>> suspended state. However PHY driver must know current
>> operational speed of PHY in order to set correct polarity of
>> wakeup events for detection. E.g. QUSB2 PHY monitors DP/DM
>> signals depending on speed is LS or FS/HS to detect resume.
>> Similarly QMP USB3 PHY in SS mode should monitor RX
>> terminations attach/detach and LFPS events depending on
>> SSPHY is active or not.
>>
>> Signed-off-by: Manu Gautam 
>> ---
>>  drivers/phy/phy-core.c  | 30 ++
>>  include/linux/phy/phy.h | 26 ++
>>  2 files changed, 56 insertions(+)
>>
>> diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
>> index b4964b0..03df2be 100644
>> --- a/drivers/phy/phy-core.c
>> +++ b/drivers/phy/phy-core.c
>> @@ -387,6 +387,36 @@ int phy_calibrate(struct phy *phy)
>>  }
>>  EXPORT_SYMBOL_GPL(phy_calibrate);
>>  
>> +int phy_notify_speed(struct phy *phy, enum phy_speed speed)
>> +{
>> +int ret;
>> +
>> +if (!phy || !phy->ops->notify_speed)
>> +return 0;
>> +
>> +mutex_lock(&phy->mutex);
>> +ret = phy->ops->notify_speed(phy, speed);
>> +mutex_unlock(&phy->mutex);
>> +
>> +return ret;
>> +}
>> +EXPORT_SYMBOL_GPL(phy_notify_speed);
>> +
>> +enum phy_speed phy_get_speed(struct phy *phy)
>> +{
>> +enum phy_speed ret;
>> +
>> +if (!phy || !phy->ops->get_speed)
>> +return PHY_SPEED_UNKNOWN;
>> +
>> +mutex_lock(&phy->mutex);
>> +ret = phy->ops->get_speed(phy);
>> +mutex_unlock(&phy->mutex);
>> +
>> +return ret;
>> +}
>> +EXPORT_SYMBOL_GPL(phy_get_speed);
> So this is equivalent to set_speed (why notify?) and get_speed. set_speed will
> most likely be invoked by USB driver? who will invoke get_speed?

I picked notify_speed as set_speed sounds like driver is going to set/program
speed related configuration in PHY. Where as the purpose of this function
is to notify phy_driver of the connection speed of established link.
USB glue drivers for Qualcomm platforms need to know USB PHYs' speed to
set correct polarity of wakeup interrupt from hardware in low power state.
 

> Thanks
> Kishon

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH v2 13/17] phy: qcom-qmp: Add support for QMP V3 USB3 PHY

2017-10-04 Thread Manu Gautam


On 9/27/2017 11:29 PM, Jack Pham wrote:
> On Wed, Sep 27, 2017 at 02:29:09PM +0530, Manu Gautam wrote:
>> QMP V3 USB3 PHY is a DP USB combo PHY with
>> dual RX/TX lanes to support type-c. There is a
>> separate block DP_COM for configuration related
>> to type-c or DP. Add support for dp_com region
>> and secondary rx/tx lanes initialization.
> Clarify "DP" as DisplayPort here?

Yes, DP implies DisplayPort. I will update commit text.

> Jack

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH v2 14/17] phy: qcom-qusb2: Set vbus sw-override signal in device mode

2017-10-05 Thread Manu Gautam
Hi Jack,

On 9/28/2017 10:23 PM, Jack Pham wrote:
> Hi Manu,
>
> On Thu, Sep 28, 2017 at 09:30:38AM +0530, Manu Gautam wrote:
>> On 9/28/2017 12:46 AM, Jack Pham wrote:
>>> On Wed, Sep 27, 2017 at 10:57:41AM -0700, Jack Pham wrote:
>>>> On Wed, Sep 27, 2017 at 02:29:10PM +0530, Manu Gautam wrote:
>>>>> VBUS signal coming from PHY must be asserted in device for
>>>>> controller to start operation or assert pull-up. For some
>>>>> platforms where VBUS line is not connected to PHY there is
>>>>> HS_PHY_CTRL register in QSCRATCH wrapper that can be used
>>>>> by software to override VBUS signal going to controller.
>>>>>
>>>>> Signed-off-by: Manu Gautam 
>>>>> ---
>>>>>  
>>>>> +static int qusb2_phy_set_mode(struct phy *phy, enum phy_mode mode)
>>>>> +{
>>>>> + struct qusb2_phy *qphy = phy_get_drvdata(phy);
>>>>> +
>>>>> + qphy->mode = mode;
>>>>> +
>>>>> + /* Update VBUS override in qscratch register */
>>>>> + if (qphy->qscratch_base) {
>>>>> + if (mode == PHY_MODE_USB_DEVICE)
>>>>> + qusb2_setbits(qphy->qscratch_base, QSCRATCH_HS_PHY_CTRL,
>>>>> +   UTMI_OTG_VBUS_VALID | SW_SESSVLD_SEL);
>>>>> + else
>>>>> + qusb2_clrbits(qphy->qscratch_base, QSCRATCH_HS_PHY_CTRL,
>>>>> +   UTMI_OTG_VBUS_VALID | SW_SESSVLD_SEL);
>>>> Wouldn't this be better off handled in the controller glue driver? Two
>>>> reasons I think this patch is unattractive:
>>>>
>>>> - qscratch_base is part of the controller's register space. Your later
>>>>   patch 16/17 ("phy: qcom-qmp: Override lane0_power_present signal in
>>>>   device mode") does a similar thing and hence both drivers have to
>>>>   ioremap() the same register resource while at the same time avoiding
>>>>   request_mem_region() (called by devm_ioremap_resource) to allow it to
>>>>   be mapped in both places.
>> Right. There is one more reason why qusb2 driver needs qscratch:
>> - During runtime suspend, it has to check linestate to set correct  polarity 
>> for dp/dm
>>   wakeup interrupt in order to detect disconnect/resume ion LS and FS/HS 
>> modes.
> Ugh, oh yeah. The way I understand we did it in our downstream driver
> is still to have the controller driver read the linestate but then pass
> the information via additional set_mode() flags which the PHY driver
> could use to correctly arm the interrupt trigger polarity.
>
> An alternative would be to access a couple of the debug QUSB2PHY
> registers that also provide a reading of the current UTMI linestate. The
> HPG mentions them vaguely, and I can't remember if we tested that
> interface or not. Assuming it works, would that be preferable to reading
> a non-PHY register here?

it looks like newer QUSB2 PHY doesn't have a register to read linestate.
QSCRATCH is the only option.
However, setting dp/dm wakeup interrupt polarity based on current linestate
isn't perfect either. It could race with any change in linestate while it was 
being
read, resulting in missed wakeup interrupt.
Same is the case with QMP PHY when trying to check for RX terminations on
suspend.
IMO PHY driver should get this info from platform glue or controller driver.
E.g. current speed -> SS, HS/FS, LS or NONE (if not in session).

Kishon,
What would you suggest here?
Should we add new calls e.g. phy_get/set_current_speed like::

diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h
index 78bb0d7..41d9ec2 100644
--- a/include/linux/phy/phy.h
+++ b/include/linux/phy/phy.h
@@ -29,6 +29,14 @@ enum phy_mode {
    PHY_MODE_USB_OTG,
 };

+enum phy_speed {
+   PHY_SPEED_INVALID,
+   PHY_SPEED_USB_LS,
+   PHY_SPEED_USB_FS_HS,
+   PHY_SPEED_USB_SS,
+};
+
 /**
  * struct phy_ops - set of function pointers for performing phy operations
  * @init: operation to be performed for initializing phy
@@ -45,6 +53,7 @@ struct phy_ops {
    int (*power_on)(struct phy *phy);
    int (*power_off)(struct phy *phy);
    int (*set_mode)(struct phy *phy, enum phy_mode mode);
+   int (*set_speed)(struct phy *phy, enum phy_speed speed);
    int (*reset)(struct phy *phy);
    struct module *owner;
 };


>>>> - VBUS override bit becomes asserted simply because the mode is changed
>>>>   to device mode but this is irrespective of the actual VBUS state. This
>>>>   could break so

[PATCH v2 01/17] phy: qcom-qmp: Fix phy pipe clock gating

2017-09-27 Thread Manu Gautam
From: Vivek Gautam 

Pipe clock comes out of the phy and is available as long as
the phy is turned on. Clock controller fails to gate this
clock after the phy is turned off and generates a warning.

/ # [   33.048561] gcc_usb3_phy_pipe_clk status stuck at 'on'
[   33.048585] [ cut here ]
[   33.052621] WARNING: CPU: 1 PID: 18 at ../drivers/clk/qcom/clk-branch.c:97 
clk_branch_wait+0xf0/0x108
[   33.057384] Modules linked in:
[   33.066497] CPU: 1 PID: 18 Comm: kworker/1:0 Tainted: GW   
4.12.0-rc7-00024-gfe926e34c36d-dirty #96
[   33.069451] Hardware name: Qualcomm Technologies, Inc. DB820c (DT)
...
[   33.278565] [] clk_branch_wait+0xf0/0x108
[   33.286375] [] clk_branch2_disable+0x28/0x34
[   33.291761] [] clk_core_disable+0x5c/0x88
[   33.297660] [] clk_core_disable_lock+0x20/0x34
[   33.303129] [] clk_disable+0x1c/0x24
[   33.309384] [] qcom_qmp_phy_poweroff+0x20/0x48
[   33.314328] [] phy_power_off+0x80/0xdc
[   33.320492] [] dwc3_core_exit+0x94/0xa0
[   33.325784] [] dwc3_suspend_common+0x50/0x60
[   33.331080] [] dwc3_runtime_suspend+0x48/0x6c
[   33.336810] [] pm_generic_runtime_suspend+0x28/0x38
[   33.342627] [] __rpm_callback+0x150/0x254
[   33.349222] [] rpm_callback+0x24/0x78
[   33.354604] [] rpm_suspend+0xe0/0x4e4
[   33.359813] [] pm_runtime_work+0xdc/0xf0
[   33.365028] [] process_one_work+0x12c/0x28c
[   33.370576] [] worker_thread+0x58/0x3b8
[   33.376393] [] kthread+0x100/0x12c
[   33.381776] [] ret_from_fork+0x10/0x50

Fix this by enabling pipe clock at the end of phy_init(), and disabling
it as the first thing in phy_exit().

Fixes: e78f3d15e115 ("phy: qcom-qmp: new qmp phy driver for qcom-chipsets")
Signed-off-by: Vivek Gautam 
Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qmp.c | 26 --
 1 file changed, 12 insertions(+), 14 deletions(-)

diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c 
b/drivers/phy/qualcomm/phy-qcom-qmp.c
index e17f035..76acaec 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.c
@@ -731,19 +731,10 @@ static int qcom_qmp_phy_poweron(struct phy *phy)
 
/* turn on regulator supplies */
ret = regulator_bulk_enable(num, qmp->vregs);
-   if (ret) {
+   if (ret)
dev_err(qmp->dev, "failed to enable regulators, err=%d\n", ret);
-   return ret;
-   }
-
-   ret = clk_prepare_enable(qphy->pipe_clk);
-   if (ret) {
-   dev_err(qmp->dev, "pipe_clk enable failed, err=%d\n", ret);
-   regulator_bulk_disable(num, qmp->vregs);
-   return ret;
-   }
 
-   return 0;
+   return ret;
 }
 
 static int qcom_qmp_phy_poweroff(struct phy *phy)
@@ -751,8 +742,6 @@ static int qcom_qmp_phy_poweroff(struct phy *phy)
struct qmp_phy *qphy = phy_get_drvdata(phy);
struct qcom_qmp *qmp = qphy->qmp;
 
-   clk_disable_unprepare(qphy->pipe_clk);
-
regulator_bulk_disable(qmp->cfg->num_vregs, qmp->vregs);
 
return 0;
@@ -915,7 +904,14 @@ static int qcom_qmp_phy_init(struct phy *phy)
goto err_pcs_ready;
}
 
-   return ret;
+   /* phy is initialized; we can turn on the pipe clock now */
+   ret = clk_prepare_enable(qphy->pipe_clk);
+   if (ret) {
+   dev_err(qmp->dev, "pipe_clk enable failed, err=%d\n", ret);
+   goto err_pcs_ready;
+   }
+
+   return 0;
 
 err_pcs_ready:
if (cfg->has_lane_rst)
@@ -936,6 +932,8 @@ static int qcom_qmp_phy_exit(struct phy *phy)
const struct qmp_phy_cfg *cfg = qmp->cfg;
int i = cfg->num_clks;
 
+   clk_disable_unprepare(qphy->pipe_clk);
+
/* PHY reset */
qphy_setbits(qphy->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v2 03/17] phy: qcom-qmp: Power-on PHY before initialization

2017-09-27 Thread Manu Gautam
PHY must be powered on before turning ON clocks and
attempting to initialize it. Driver is exposing
separate init and power_on routines for this.
Apparently USB dwc3 core driver performs power-on after
init. Also, poweron and init for QMP PHY need to be
executed together always, hence remove poweron callback
from phy_ops and explicitly perform this from com_init,
similar changes needed for poweroff. On similar lines move
clk_enable from init to com_init which can be called once
for multi lane PHYs.

Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qmp.c | 61 +
 1 file changed, 21 insertions(+), 40 deletions(-)

diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c 
b/drivers/phy/qualcomm/phy-qcom-qmp.c
index 90794dd..2f427e3 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.c
@@ -720,33 +720,6 @@ static void qcom_qmp_phy_configure(void __iomem *base,
}
 }
 
-static int qcom_qmp_phy_poweron(struct phy *phy)
-{
-   struct qmp_phy *qphy = phy_get_drvdata(phy);
-   struct qcom_qmp *qmp = qphy->qmp;
-   int num = qmp->cfg->num_vregs;
-   int ret;
-
-   dev_vdbg(&phy->dev, "Powering on QMP phy\n");
-
-   /* turn on regulator supplies */
-   ret = regulator_bulk_enable(num, qmp->vregs);
-   if (ret)
-   dev_err(qmp->dev, "failed to enable regulators, err=%d\n", ret);
-
-   return ret;
-}
-
-static int qcom_qmp_phy_poweroff(struct phy *phy)
-{
-   struct qmp_phy *qphy = phy_get_drvdata(phy);
-   struct qcom_qmp *qmp = qphy->qmp;
-
-   regulator_bulk_disable(qmp->cfg->num_vregs, qmp->vregs);
-
-   return 0;
-}
-
 static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
 {
const struct qmp_phy_cfg *cfg = qmp->cfg;
@@ -759,6 +732,19 @@ static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
return 0;
}
 
+   /* turn on regulator supplies */
+   ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs);
+   if (ret) {
+   mutex_unlock(&qmp->phy_mutex);
+   return ret;
+   }
+
+   ret = clk_bulk_prepare_enable(cfg->num_clks, qmp->clks);
+   if (ret) {
+   dev_err(qmp->dev, "failed to enable clks, err=%d\n", ret);
+   goto err_clk_enable;
+   }
+
for (i = 0; i < cfg->num_resets; i++) {
ret = reset_control_deassert(qmp->resets[i]);
if (ret) {
@@ -803,6 +789,9 @@ static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
 err_rst:
while (--i >= 0)
reset_control_assert(qmp->resets[i]);
+   clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks);
+err_clk_enable:
+   regulator_bulk_disable(cfg->num_vregs, qmp->vregs);
mutex_unlock(&qmp->phy_mutex);
 
return ret;
@@ -832,6 +821,10 @@ static int qcom_qmp_phy_com_exit(struct qcom_qmp *qmp)
while (--i >= 0)
reset_control_assert(qmp->resets[i]);
 
+   clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks);
+
+   regulator_bulk_disable(cfg->num_vregs, qmp->vregs);
+
mutex_unlock(&qmp->phy_mutex);
 
return 0;
@@ -852,15 +845,9 @@ static int qcom_qmp_phy_init(struct phy *phy)
 
dev_vdbg(qmp->dev, "Initializing QMP phy\n");
 
-   ret = clk_bulk_prepare_enable(cfg->num_clks, qmp->clks);
-   if (ret) {
-   dev_err(qmp->dev, "failed to enable clks, err=%d\n", ret);
-   return ret;
-   }
-
ret = qcom_qmp_phy_com_init(qmp);
if (ret)
-   goto err_com_init;
+   return ret;
 
if (cfg->has_lane_rst) {
ret = reset_control_deassert(qphy->lane_rst);
@@ -915,8 +902,6 @@ static int qcom_qmp_phy_init(struct phy *phy)
reset_control_assert(qphy->lane_rst);
 err_lane_rst:
qcom_qmp_phy_com_exit(qmp);
-err_com_init:
-   clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks);
 
return ret;
 }
@@ -943,8 +928,6 @@ static int qcom_qmp_phy_exit(struct phy *phy)
 
qcom_qmp_phy_com_exit(qmp);
 
-   clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks);
-
return 0;
 }
 
@@ -1057,8 +1040,6 @@ static int phy_pipe_clk_register(struct qcom_qmp *qmp, 
struct device_node *np)
 static const struct phy_ops qcom_qmp_phy_gen_ops = {
.init   = qcom_qmp_phy_init,
.exit   = qcom_qmp_phy_exit,
-   .power_on   = qcom_qmp_phy_poweron,
-   .power_off  = qcom_qmp_phy_poweroff,
.owner  = THIS_MODULE,
 };
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v2 02/17] phy: qcom-qmp: Adapt to clk_bulk_* APIs

2017-09-27 Thread Manu Gautam
From: Vivek Gautam 

Move from using array of clocks to clk_bulk_* APIs that
are available now.

Signed-off-by: Vivek Gautam 
Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qmp.c | 50 -
 1 file changed, 16 insertions(+), 34 deletions(-)

diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c 
b/drivers/phy/qualcomm/phy-qcom-qmp.c
index 76acaec..90794dd 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.c
@@ -555,7 +555,7 @@ struct qcom_qmp {
struct device *dev;
void __iomem *serdes;
 
-   struct clk **clks;
+   struct clk_bulk_data *clks;
struct reset_control **resets;
struct regulator_bulk_data *vregs;
 
@@ -848,22 +848,19 @@ static int qcom_qmp_phy_init(struct phy *phy)
void __iomem *pcs = qphy->pcs;
void __iomem *status;
unsigned int mask, val;
-   int ret, i;
+   int ret;
 
dev_vdbg(qmp->dev, "Initializing QMP phy\n");
 
-   for (i = 0; i < qmp->cfg->num_clks; i++) {
-   ret = clk_prepare_enable(qmp->clks[i]);
-   if (ret) {
-   dev_err(qmp->dev, "failed to enable %s clk, err=%d\n",
-   qmp->cfg->clk_list[i], ret);
-   goto err_clk;
-   }
+   ret = clk_bulk_prepare_enable(cfg->num_clks, qmp->clks);
+   if (ret) {
+   dev_err(qmp->dev, "failed to enable clks, err=%d\n", ret);
+   return ret;
}
 
ret = qcom_qmp_phy_com_init(qmp);
if (ret)
-   goto err_clk;
+   goto err_com_init;
 
if (cfg->has_lane_rst) {
ret = reset_control_deassert(qphy->lane_rst);
@@ -918,9 +915,8 @@ static int qcom_qmp_phy_init(struct phy *phy)
reset_control_assert(qphy->lane_rst);
 err_lane_rst:
qcom_qmp_phy_com_exit(qmp);
-err_clk:
-   while (--i >= 0)
-   clk_disable_unprepare(qmp->clks[i]);
+err_com_init:
+   clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks);
 
return ret;
 }
@@ -930,7 +926,6 @@ static int qcom_qmp_phy_exit(struct phy *phy)
struct qmp_phy *qphy = phy_get_drvdata(phy);
struct qcom_qmp *qmp = qphy->qmp;
const struct qmp_phy_cfg *cfg = qmp->cfg;
-   int i = cfg->num_clks;
 
clk_disable_unprepare(qphy->pipe_clk);
 
@@ -948,8 +943,7 @@ static int qcom_qmp_phy_exit(struct phy *phy)
 
qcom_qmp_phy_com_exit(qmp);
 
-   while (--i >= 0)
-   clk_disable_unprepare(qmp->clks[i]);
+   clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks);
 
return 0;
 }
@@ -998,29 +992,17 @@ static int qcom_qmp_phy_reset_init(struct device *dev)
 static int qcom_qmp_phy_clk_init(struct device *dev)
 {
struct qcom_qmp *qmp = dev_get_drvdata(dev);
-   int ret, i;
+   int num = qmp->cfg->num_clks;
+   int i;
 
-   qmp->clks = devm_kcalloc(dev, qmp->cfg->num_clks,
-sizeof(*qmp->clks), GFP_KERNEL);
+   qmp->clks = devm_kcalloc(dev, num, sizeof(*qmp->clks), GFP_KERNEL);
if (!qmp->clks)
return -ENOMEM;
 
-   for (i = 0; i < qmp->cfg->num_clks; i++) {
-   struct clk *_clk;
-   const char *name = qmp->cfg->clk_list[i];
-
-   _clk = devm_clk_get(dev, name);
-   if (IS_ERR(_clk)) {
-   ret = PTR_ERR(_clk);
-   if (ret != -EPROBE_DEFER)
-   dev_err(dev, "failed to get %s clk, %d\n",
-   name, ret);
-   return ret;
-   }
-   qmp->clks[i] = _clk;
-   }
+   for (i = 0; i < num; i++)
+   qmp->clks->id = qmp->cfg->clk_list[i];
 
-   return 0;
+   return devm_clk_bulk_get(dev, num, qmp->clks);
 }
 
 /*
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v2 05/17] phy: qcom-qmp: Fix PHY block reset sequence

2017-09-27 Thread Manu Gautam
PHY block or asynchronous reset requires signal
to be asserted before de-asserting. Driver is only
de-asserting signal which is already low, hence
reset operation is a no-op. Fix this by asserting
signal first. Also, resetting requires PHY clocks
to be turned ON only after reset is finished. Fix
that as well.

Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qmp.c | 28 +++-
 1 file changed, 19 insertions(+), 9 deletions(-)

diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c 
b/drivers/phy/qualcomm/phy-qcom-qmp.c
index 2f427e3..aa27757 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.c
@@ -739,13 +739,16 @@ static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
return ret;
}
 
-   ret = clk_bulk_prepare_enable(cfg->num_clks, qmp->clks);
-   if (ret) {
-   dev_err(qmp->dev, "failed to enable clks, err=%d\n", ret);
-   goto err_clk_enable;
+   for (i = 0; i < cfg->num_resets; i++) {
+   ret = reset_control_assert(qmp->resets[i]);
+   if (ret) {
+   dev_err(qmp->dev, "%s reset assert failed\n",
+   cfg->reset_list[i]);
+   goto err_rst_assert;
+   }
}
 
-   for (i = 0; i < cfg->num_resets; i++) {
+   for (i = cfg->num_resets - 1; i >= 0; i--) {
ret = reset_control_deassert(qmp->resets[i]);
if (ret) {
dev_err(qmp->dev, "%s reset deassert failed\n",
@@ -754,6 +757,12 @@ static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
}
}
 
+   ret = clk_bulk_prepare_enable(cfg->num_clks, qmp->clks);
+   if (ret) {
+   dev_err(qmp->dev, "failed to enable clks, err=%d\n", ret);
+   goto err_rst;
+   }
+
if (cfg->has_phy_com_ctrl)
qphy_setbits(serdes, cfg->regs[QPHY_COM_POWER_DOWN_CONTROL],
 SW_PWRDN);
@@ -778,7 +787,7 @@ static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
if (ret) {
dev_err(qmp->dev,
"phy common block init timed-out\n");
-   goto err_rst;
+   goto err_com_init;
}
}
 
@@ -786,11 +795,12 @@ static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
 
return 0;
 
+err_com_init:
+   clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks);
 err_rst:
-   while (--i >= 0)
+   while (++i < cfg->num_resets)
reset_control_assert(qmp->resets[i]);
-   clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks);
-err_clk_enable:
+err_rst_assert:
regulator_bulk_disable(cfg->num_vregs, qmp->vregs);
mutex_unlock(&qmp->phy_mutex);
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v2 06/17] phy: qcom-qmp: Move SERDES/PCS START after PHY reset

2017-09-27 Thread Manu Gautam
Driver is currently performing PHY reset after starting
SERDES/PCS. As per hardware datasheet reset must be done
before starting PHY. Hence, update the sequence.

Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qmp.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c 
b/drivers/phy/qualcomm/phy-qcom-qmp.c
index aa27757..263cf50 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.c
@@ -882,12 +882,12 @@ static int qcom_qmp_phy_init(struct phy *phy)
if (cfg->has_pwrdn_delay)
usleep_range(cfg->pwrdn_delay_min, cfg->pwrdn_delay_max);
 
-   /* start SerDes and Phy-Coding-Sublayer */
-   qphy_setbits(pcs, cfg->regs[QPHY_START_CTRL], cfg->start_ctrl);
-
/* Pull PHY out of reset state */
qphy_clrbits(pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
 
+   /* start SerDes and Phy-Coding-Sublayer */
+   qphy_setbits(pcs, cfg->regs[QPHY_START_CTRL], cfg->start_ctrl);
+
status = pcs + cfg->regs[QPHY_PCS_READY_STATUS];
mask = cfg->mask_pcs_ready;
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v2 07/17] phy: qcom-qusb2: Add support for different register layouts

2017-09-27 Thread Manu Gautam
New version of QUSB2 PHY has some registers offset changed.
Add support to have register layout for a target and update
the same in phy_configuration.

Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qusb2.c | 131 --
 1 file changed, 95 insertions(+), 36 deletions(-)

diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c 
b/drivers/phy/qualcomm/phy-qcom-qusb2.c
index 4a5b2a1..c0c5358 100644
--- a/drivers/phy/qualcomm/phy-qcom-qusb2.c
+++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c
@@ -37,17 +37,10 @@
 #define QUSB2PHY_PLL_AUTOPGM_CTL1  0x1c
 #define QUSB2PHY_PLL_PWR_CTRL  0x18
 
-#define QUSB2PHY_PLL_STATUS0x38
+/* QUSB2PHY_PLL_STATUS register bits */
 #define PLL_LOCKED BIT(5)
 
-#define QUSB2PHY_PORT_TUNE10x80
-#define QUSB2PHY_PORT_TUNE20x84
-#define QUSB2PHY_PORT_TUNE30x88
-#define QUSB2PHY_PORT_TUNE40x8c
-#define QUSB2PHY_PORT_TUNE50x90
-#define QUSB2PHY_PORT_TEST20x9c
-
-#define QUSB2PHY_PORT_POWERDOWN0xb4
+/* QUSB2PHY_PORT_POWERDOWN register bits */
 #define CLAMP_N_EN BIT(5)
 #define FREEZIO_N  BIT(1)
 #define POWER_DOWN BIT(0)
@@ -59,6 +52,11 @@
 struct qusb2_phy_init_tbl {
unsigned int offset;
unsigned int val;
+   /*
+* register part of layout ?
+* if yes, then offset gives index in the reg-layout
+*/
+   int in_layout;
 };
 
 #define QUSB2_PHY_INIT_CFG(o, v) \
@@ -67,15 +65,50 @@ struct qusb2_phy_init_tbl {
.val = v,   \
}
 
+#define QUSB2_PHY_INIT_CFG_L(o, v) \
+   {   \
+   .offset = o,\
+   .val = v,   \
+   .in_layout = 1, \
+   }
+
+/* set of registers with offsets different per-PHY */
+enum qusb2phy_reg_layout {
+   QUSB2PHY_PLL_STATUS,
+   QUSB2PHY_PORT_TUNE1,
+   QUSB2PHY_PORT_TUNE2,
+   QUSB2PHY_PORT_TUNE3,
+   QUSB2PHY_PORT_TUNE4,
+   QUSB2PHY_PORT_TUNE5,
+   QUSB2PHY_PORT_TEST1,
+   QUSB2PHY_PORT_TEST2,
+   QUSB2PHY_PORT_POWERDOWN,
+   QUSB2PHY_INTR_CTRL,
+};
+
+static const unsigned int msm8996_regs_layout[] = {
+   [QUSB2PHY_PLL_STATUS]   = 0x38,
+   [QUSB2PHY_PORT_TUNE1]   = 0x80,
+   [QUSB2PHY_PORT_TUNE2]   = 0x84,
+   [QUSB2PHY_PORT_TUNE3]   = 0x88,
+   [QUSB2PHY_PORT_TUNE4]   = 0x8c,
+   [QUSB2PHY_PORT_TUNE5]   = 0x90,
+   [QUSB2PHY_PORT_TEST2]   = 0x9c,
+   [QUSB2PHY_PORT_POWERDOWN]   = 0xb4,
+};
+
 static const struct qusb2_phy_init_tbl msm8996_init_tbl[] = {
-   QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TUNE1, 0xf8),
-   QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TUNE2, 0xb3),
-   QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TUNE3, 0x83),
-   QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TUNE4, 0xc0),
+   QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE1, 0xf8),
+   QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE2, 0xb3),
+   QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE3, 0x83),
+   QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE4, 0xc0),
+
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_TUNE, 0x30),
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_USER_CTL1, 0x79),
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_USER_CTL2, 0x21),
-   QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TEST2, 0x14),
+
+   QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TEST2, 0x14),
+
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_AUTOPGM_CTL1, 0x9f),
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_PWR_CTRL, 0x00),
 };
@@ -86,11 +119,24 @@ struct qusb2_phy_cfg {
unsigned int tbl_num;
/* offset to PHY_CLK_SCHEME register in TCSR map */
unsigned int clk_scheme_offset;
+
+   /* array of registers with different offsets */
+   const unsigned int *regs;
+   unsigned int mask_core_ready;
+   unsigned int disable_ctrl;
+
+   /* true if PHY has PLL_TEST register to select clk_scheme */
+   bool has_pll_test;
 };
 
 static const struct qusb2_phy_cfg msm8996_phy_cfg = {
-   .tbl = msm8996_init_tbl,
-   .tbl_num = ARRAY_SIZE(msm8996_init_tbl),
+   .tbl= msm8996_init_tbl,
+   .tbl_num= ARRAY_SIZE(msm8996_init_tbl),
+   .regs   = msm8996_regs_layout,
+
+   .has_pll_test   = true,
+   .disable_ctrl   = (CLAMP_N_EN | FREEZIO_N | POWER_DOWN),
+   .mask_core_ready = PLL_LOCKED,
 };
 
 static const char * const qusb2_phy_vreg_names[] = {
@@ -160,12 +206,17 @@ static inline void qusb2_clrbits(void __iomem *base, u32 
offset, u32 val)
 
 static inline
 void qcom_qusb2_phy_configure(void __iomem *base,
+ const unsigned int *regs,
  const struct qusb2_phy_init_tbl tbl[], int num)
 {
int i;
 
-   for (i = 0; i < num; i++)
-   writel(tbl[i].val, base + tbl[i].offset);
+   for (i = 0; i < num; i++) {
+   if 

[PATCH v2 04/17] phy: qcom-qusb2: Power-on PHY before initialization

2017-09-27 Thread Manu Gautam
PHY must be powered on before turning ON clocks and
attempting to initialize it. Driver is exposing
separate init and power_on routines for this.
Apparently USB dwc3 core driver performs power-on
after init. Also, poweron and init for QUSB2 PHY
need to be executed together always, hence remove
poweron callback from phy_ops and explicitly perform
this from init, similar changes needed for poweroff.

Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qusb2.c | 47 +++
 1 file changed, 15 insertions(+), 32 deletions(-)

diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c 
b/drivers/phy/qualcomm/phy-qcom-qusb2.c
index 6c57524..4a5b2a1 100644
--- a/drivers/phy/qualcomm/phy-qcom-qusb2.c
+++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c
@@ -195,54 +195,31 @@ static void qusb2_phy_set_tune2_param(struct qusb2_phy 
*qphy)
qusb2_setbits(qphy->base, QUSB2PHY_PORT_TUNE2, val[0] << 0x4);
 }
 
-static int qusb2_phy_poweron(struct phy *phy)
+static int qusb2_phy_init(struct phy *phy)
 {
struct qusb2_phy *qphy = phy_get_drvdata(phy);
-   int num = ARRAY_SIZE(qphy->vregs);
+   unsigned int val;
+   unsigned int clk_scheme;
int ret;
 
-   dev_vdbg(&phy->dev, "%s(): Powering-on QUSB2 phy\n", __func__);
+   dev_vdbg(&phy->dev, "%s(): Initializing QUSB2 phy\n", __func__);
 
/* turn on regulator supplies */
-   ret = regulator_bulk_enable(num, qphy->vregs);
+   ret = regulator_bulk_enable(ARRAY_SIZE(qphy->vregs), qphy->vregs);
if (ret)
return ret;
 
ret = clk_prepare_enable(qphy->iface_clk);
if (ret) {
dev_err(&phy->dev, "failed to enable iface_clk, %d\n", ret);
-   regulator_bulk_disable(num, qphy->vregs);
-   return ret;
+   goto poweroff_phy;
}
 
-   return 0;
-}
-
-static int qusb2_phy_poweroff(struct phy *phy)
-{
-   struct qusb2_phy *qphy = phy_get_drvdata(phy);
-
-   clk_disable_unprepare(qphy->iface_clk);
-
-   regulator_bulk_disable(ARRAY_SIZE(qphy->vregs), qphy->vregs);
-
-   return 0;
-}
-
-static int qusb2_phy_init(struct phy *phy)
-{
-   struct qusb2_phy *qphy = phy_get_drvdata(phy);
-   unsigned int val;
-   unsigned int clk_scheme;
-   int ret;
-
-   dev_vdbg(&phy->dev, "%s(): Initializing QUSB2 phy\n", __func__);
-
/* enable ahb interface clock to program phy */
ret = clk_prepare_enable(qphy->cfg_ahb_clk);
if (ret) {
dev_err(&phy->dev, "failed to enable cfg ahb clock, %d\n", ret);
-   return ret;
+   goto disable_iface_clk;
}
 
/* Perform phy reset */
@@ -344,6 +321,11 @@ static int qusb2_phy_init(struct phy *phy)
reset_control_assert(qphy->phy_reset);
 disable_ahb_clk:
clk_disable_unprepare(qphy->cfg_ahb_clk);
+disable_iface_clk:
+   clk_disable_unprepare(qphy->iface_clk);
+poweroff_phy:
+   regulator_bulk_disable(ARRAY_SIZE(qphy->vregs), qphy->vregs);
+
return ret;
 }
 
@@ -361,6 +343,9 @@ static int qusb2_phy_exit(struct phy *phy)
reset_control_assert(qphy->phy_reset);
 
clk_disable_unprepare(qphy->cfg_ahb_clk);
+   clk_disable_unprepare(qphy->iface_clk);
+
+   regulator_bulk_disable(ARRAY_SIZE(qphy->vregs), qphy->vregs);
 
return 0;
 }
@@ -368,8 +353,6 @@ static int qusb2_phy_exit(struct phy *phy)
 static const struct phy_ops qusb2_phy_gen_ops = {
.init   = qusb2_phy_init,
.exit   = qusb2_phy_exit,
-   .power_on   = qusb2_phy_poweron,
-   .power_off  = qusb2_phy_poweroff,
.owner  = THIS_MODULE,
 };
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v2 09/17] phy: qcom-qusb2: Add support for QUSB2 V2 version

2017-09-27 Thread Manu Gautam
Use register layout to add additional registers present
on QUSB2 PHY V2 version for PHY initialization.
Other than new registers on V2, following two register's
offset and bit definitions are different: POWERDOWN control
and PLL_STATUS.

Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qusb2.c | 64 +++
 1 file changed, 64 insertions(+)

diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c 
b/drivers/phy/qualcomm/phy-qcom-qusb2.c
index c0c5358..bda1f4c 100644
--- a/drivers/phy/qualcomm/phy-qcom-qusb2.c
+++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c
@@ -40,15 +40,34 @@
 /* QUSB2PHY_PLL_STATUS register bits */
 #define PLL_LOCKED BIT(5)
 
+/* QUSB2PHY_PLL_COMMON_STATUS_ONE register bits */
+#define CORE_READY_STATUS  BIT(0)
+
 /* QUSB2PHY_PORT_POWERDOWN register bits */
 #define CLAMP_N_EN BIT(5)
 #define FREEZIO_N  BIT(1)
 #define POWER_DOWN BIT(0)
 
+/* QUSB2PHY_PWR_CTRL1 register bits */
+#define PWR_CTRL1_VREF_SUPPLY_TRIM BIT(5)
+#define PWR_CTRL1_CLAMP_N_EN   BIT(1)
+
 #define QUSB2PHY_REFCLK_ENABLE BIT(0)
 
 #define PHY_CLK_SCHEME_SEL BIT(0)
 
+#defineQUSB2PHY_PLL_ANALOG_CONTROLS_TWO0x04
+#defineQUSB2PHY_PLL_CLOCK_INVERTERS0x18c
+#defineQUSB2PHY_PLL_CMODE  0x2c
+#defineQUSB2PHY_PLL_LOCK_DELAY 0x184
+#defineQUSB2PHY_PLL_DIGITAL_TIMERS_TWO 0xb4
+#defineQUSB2PHY_PLL_BIAS_CONTROL_1 0x194
+#defineQUSB2PHY_PLL_BIAS_CONTROL_2 0x198
+#defineQUSB2PHY_PWR_CTRL2  0x214
+#defineQUSB2PHY_IMP_CTRL1  0x220
+#defineQUSB2PHY_IMP_CTRL2  0x224
+#defineQUSB2PHY_CHG_CTRL2  0x23c
+
 struct qusb2_phy_init_tbl {
unsigned int offset;
unsigned int val;
@@ -113,6 +132,38 @@ enum qusb2phy_reg_layout {
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_PWR_CTRL, 0x00),
 };
 
+static const unsigned int qusb2_v2_regs_layout[] = {
+   [QUSB2PHY_PLL_STATUS]   = 0x1a0,
+   [QUSB2PHY_PORT_TUNE1]   = 0x240,
+   [QUSB2PHY_PORT_TUNE2]   = 0x244,
+   [QUSB2PHY_PORT_TUNE3]   = 0x248,
+   [QUSB2PHY_PORT_TUNE4]   = 0x24c,
+   [QUSB2PHY_PORT_TUNE5]   = 0x250,
+   [QUSB2PHY_PORT_TEST2]   = 0x258,
+   [QUSB2PHY_PORT_POWERDOWN]   = 0x210,
+};
+
+static const struct qusb2_phy_init_tbl qusb2_v2_init_tbl[] = {
+   QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_ANALOG_CONTROLS_TWO, 0x03),
+   QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_CLOCK_INVERTERS, 0x7c),
+   QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_CMODE, 0x80),
+   QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_LOCK_DELAY, 0x0a),
+   QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_DIGITAL_TIMERS_TWO, 0x19),
+   QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_BIAS_CONTROL_1, 0x40),
+   QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_BIAS_CONTROL_2, 0x20),
+   QUSB2_PHY_INIT_CFG(QUSB2PHY_PWR_CTRL2, 0x21),
+   QUSB2_PHY_INIT_CFG(QUSB2PHY_IMP_CTRL1, 0x0),
+   QUSB2_PHY_INIT_CFG(QUSB2PHY_IMP_CTRL2, 0x58),
+
+   QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE1, 0x30),
+   QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE2, 0x29),
+   QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE3, 0xca),
+   QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE4, 0x04),
+   QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE5, 0x03),
+
+   QUSB2_PHY_INIT_CFG(QUSB2PHY_CHG_CTRL2, 0x0),
+};
+
 struct qusb2_phy_cfg {
const struct qusb2_phy_init_tbl *tbl;
/* number of entries in the table */
@@ -139,6 +190,16 @@ struct qusb2_phy_cfg {
.mask_core_ready = PLL_LOCKED,
 };
 
+static const struct qusb2_phy_cfg qusb2_v2_phy_cfg = {
+   .tbl= qusb2_v2_init_tbl,
+   .tbl_num= ARRAY_SIZE(qusb2_v2_init_tbl),
+   .regs   = qusb2_v2_regs_layout,
+
+   .disable_ctrl   = (PWR_CTRL1_VREF_SUPPLY_TRIM | PWR_CTRL1_CLAMP_N_EN |
+  POWER_DOWN),
+   .mask_core_ready = CORE_READY_STATUS,
+};
+
 static const char * const qusb2_phy_vreg_names[] = {
"vdda-pll", "vdda-phy-dpdm",
 };
@@ -419,6 +480,9 @@ static int qusb2_phy_exit(struct phy *phy)
{
.compatible = "qcom,msm8996-qusb2-phy",
.data   = &msm8996_phy_cfg,
+   }, {
+   .compatible = "qcom,qusb2-v2-phy",
+   .data   = &qusb2_v2_phy_cfg,
},
{ },
 };
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v2 13/17] phy: qcom-qmp: Add support for QMP V3 USB3 PHY

2017-09-27 Thread Manu Gautam
QMP V3 USB3 PHY is a DP USB combo PHY with
dual RX/TX lanes to support type-c. There is a
separate block DP_COM for configuration related
to type-c or DP. Add support for dp_com region
and secondary rx/tx lanes initialization.

Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qmp.c | 222 +++-
 1 file changed, 219 insertions(+), 3 deletions(-)

diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c 
b/drivers/phy/qualcomm/phy-qcom-qmp.c
index 15a734f..d4e1436 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.c
@@ -47,6 +47,21 @@
 /* QPHY_COM_PCS_READY_STATUS bit */
 #define PCS_READY  BIT(0)
 
+/* QPHY_V3_DP_COM_RESET_OVRD_CTRL register bits */
+/* DP PHY soft reset */
+#define SW_DPPHY_RESET BIT(0)
+/* mux to select DP PHY reset control, 0:HW control, 1: software reset */
+#define SW_DPPHY_RESET_MUX BIT(1)
+/* USB3 PHY soft reset */
+#define SW_USB3PHY_RESET   BIT(2)
+/* mux to select USB3 PHY reset control, 0:HW control, 1: software reset */
+#define SW_USB3PHY_RESET_MUX   BIT(3)
+
+/* QPHY_V3_DP_COM_PHY_MODE_CTRL register bits */
+#define USB3_MODE  BIT(0) /* enables USB3 mode */
+#define DP_MODEBIT(1) /* enables DP 
mode */
+
+
 #define PHY_INIT_COMPLETE_TIMEOUT  1000
 #define POWER_DOWN_DELAY_US_MIN10
 #define POWER_DOWN_DELAY_US_MAX11
@@ -122,6 +137,12 @@ enum qphy_reg_layout {
[QPHY_PCS_READY_STATUS] = 0x17c,
 };
 
+static const unsigned int qmp_v3_usb3phy_regs_layout[] = {
+   [QPHY_SW_RESET] = 0x00,
+   [QPHY_START_CTRL]   = 0x08,
+   [QPHY_PCS_READY_STATUS] = 0x174,
+};
+
 static const struct qmp_phy_init_tbl msm8996_pcie_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x1c),
QMP_PHY_INIT_CFG(QSERDES_COM_CLK_ENABLE1, 0x10),
@@ -350,6 +371,112 @@ enum qphy_reg_layout {
QMP_PHY_INIT_CFG_L(QPHY_START_CTRL, 0x3),
 };
 
+static const struct qmp_phy_init_tbl qmp_v3_usb3_serdes_tbl[] = {
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_IVCO, 0x07),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_EN_SEL, 0x14),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x08),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x30),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYS_CLK_CTRL, 0x02),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_RESETSM_CNTRL2, 0x08),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_CONFIG, 0x16),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_SVS_MODE_CLK_SEL, 0x01),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_HSCLK_SEL, 0x80),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_DEC_START_MODE0, 0x82),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START1_MODE0, 0xab),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START2_MODE0, 0xea),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START3_MODE0, 0x02),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_CP_CTRL_MODE0, 0x06),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_RCTRL_MODE0, 0x16),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_CCTRL_MODE0, 0x36),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE0, 0x00),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE0, 0x3f),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE2_MODE0, 0x01),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE1_MODE0, 0xc9),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORECLK_DIV_MODE0, 0x0a),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP3_MODE0, 0x00),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP2_MODE0, 0x34),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP1_MODE0, 0x15),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_EN, 0x04),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORE_CLK_EN, 0x00),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_CFG, 0x00),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_MAP, 0x00),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_BUF_ENABLE, 0x0a),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_EN_CENTER, 0x01),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER1, 0x31),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER2, 0x01),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER1, 0x00),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER2, 0x00),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE1, 0x85),
+   QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE2, 0x07),
+};
+
+static const struct qmp_phy_init_tbl qmp_v3_usb3_tx_tbl[] = {
+   QMP_PHY_INIT_CFG(QSERDES_V3_TX_HIGHZ_DRVR_EN, 0x10),
+   QMP_PHY_INIT_CFG(QSERDES_V3_TX_RCV_DETECT_LVL_2, 0x12),
+   QMP_PHY_INIT_CFG(QSERDES_V3_TX_LANE_MODE_1, 0x16),
+   QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_RX, 0x09),
+   QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX, 0x06),
+};
+
+static const struct qmp_phy_init_tbl qmp_v3_usb3_rx_tbl

[PATCH v2 12/17] dt-bindings: phy-qcom-qmp: Update bindings for QMP V3 USB PHY

2017-09-27 Thread Manu Gautam
Update compatible string and clock names for QMP version V3
USB PHY.

Signed-off-by: Manu Gautam 
---
 Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt 
b/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt
index b6a9f2b..dcf1b8f 100644
--- a/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt
+++ b/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt
@@ -8,7 +8,8 @@ Required properties:
  - compatible: compatible list, contains:
   "qcom,ipq8074-qmp-pcie-phy" for PCIe phy on IPQ8074
   "qcom,msm8996-qmp-pcie-phy" for 14nm PCIe phy on msm8996,
-  "qcom,msm8996-qmp-usb3-phy" for 14nm USB3 phy on msm8996.
+  "qcom,msm8996-qmp-usb3-phy" for 14nm USB3 phy on msm8996,
+  "qcom,qmp-v3-usb3-phy" for USB3 QMP V3 phy.
 
  - reg: offset and length of register set for PHY's common serdes block.
 
@@ -25,10 +26,13 @@ Required properties:
  - clock-names: "cfg_ahb" for phy config clock,
"aux" for phy aux clock,
"ref" for 19.2 MHz ref clk,
+   "com_aux" for phy common block aux clock,
For "qcom,msm8996-qmp-pcie-phy" must contain:
"aux", "cfg_ahb", "ref".
For "qcom,msm8996-qmp-usb3-phy" must contain:
"aux", "cfg_ahb", "ref".
+   For "qcom,qmp-v3-usb3-phy" must contain:
+   "aux", "cfg_ahb", "ref", "com_aux".
 
  - resets: a list of phandles and reset controller specifier pairs,
   one for each entry in reset-names.
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v2 16/17] phy: qcom-qmp: Override lane0_power_present signal in device mode

2017-09-27 Thread Manu Gautam
lane0_power_present signal must be asserted of hardware to
operate properly in SS device mode. On some platforms where VBUS
line is not connected to SS QMP PHY there is SS_PHY_CTRL register
in QSCRATCH wrapper that can be used by software to override VBUS.

Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qmp.c | 38 +
 1 file changed, 38 insertions(+)

diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c 
b/drivers/phy/qualcomm/phy-qcom-qmp.c
index d4e1436..1403de3 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.c
@@ -61,6 +61,9 @@
 #define USB3_MODE  BIT(0) /* enables USB3 mode */
 #define DP_MODEBIT(1) /* enables DP 
mode */
 
+/* QSCRATCH register bits */
+#define QSCRATCH_SS_PHY_CTRL   0x30
+#define LANE0_PWR_PRESENT  BIT(24)
 
 #define PHY_INIT_COMPLETE_TIMEOUT  1000
 #define POWER_DOWN_DELAY_US_MIN10
@@ -558,6 +561,7 @@ struct qmp_phy {
  * @dev: device
  * @serdes: iomapped memory space for phy's serdes
  * @dp_com: iomapped memory space for phy's dp_com control block
+ * @qscratch_base: iomapped memory space for qscratch region
  *
  * @clks: array of clocks required by phy
  * @resets: array of resets required by phy
@@ -572,6 +576,7 @@ struct qcom_qmp {
struct device *dev;
void __iomem *serdes;
void __iomem *dp_com;
+   void __iomem *qscratch_base;
 
struct clk_bulk_data *clks;
struct reset_control **resets;
@@ -582,6 +587,7 @@ struct qcom_qmp {
 
struct mutex phy_mutex;
int init_count;
+   enum phy_mode mode;
 };
 
 static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val)
@@ -1024,6 +1030,26 @@ static int qcom_qmp_phy_exit(struct phy *phy)
return 0;
 }
 
+static int qcom_qmp_phy_set_mode(struct phy *phy, enum phy_mode mode)
+{
+   struct qmp_phy *qphy = phy_get_drvdata(phy);
+   struct qcom_qmp *qmp = qphy->qmp;
+
+   qmp->mode = mode;
+
+   /* Update VBUS override in qscratch register */
+   if (qmp->qscratch_base) {
+   if (mode == PHY_MODE_USB_DEVICE)
+   qphy_setbits(qmp->qscratch_base, QSCRATCH_SS_PHY_CTRL,
+LANE0_PWR_PRESENT);
+   else
+   qphy_clrbits(qmp->qscratch_base, QSCRATCH_SS_PHY_CTRL,
+LANE0_PWR_PRESENT);
+   }
+
+   return 0;
+}
+
 static int qcom_qmp_phy_vreg_init(struct device *dev)
 {
struct qcom_qmp *qmp = dev_get_drvdata(dev);
@@ -1133,6 +1159,7 @@ static int phy_pipe_clk_register(struct qcom_qmp *qmp, 
struct device_node *np)
 static const struct phy_ops qcom_qmp_phy_gen_ops = {
.init   = qcom_qmp_phy_init,
.exit   = qcom_qmp_phy_exit,
+   .set_mode   = qcom_qmp_phy_set_mode,
.owner  = THIS_MODULE,
 };
 
@@ -1273,7 +1300,18 @@ static int qcom_qmp_phy_probe(struct platform_device 
*pdev)
qmp->dp_com = base;
}
 
+   /* Check if platform uses qscratch wrapper */
+   res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qscratch");
+   if (res) {
+   /* Can't request region as used by other phy and glue drivers */
+   qmp->qscratch_base = devm_ioremap(dev, res->start,
+  resource_size(res));
+   if (IS_ERR(qmp->qscratch_base))
+   return PTR_ERR(qmp->qscratch_base);
+   }
+
mutex_init(&qmp->phy_mutex);
+   qmp->mode = PHY_MODE_INVALID;
 
ret = qcom_qmp_phy_clk_init(dev);
if (ret)
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v2 15/17] phy: qcom-qusb2: Add support for runtime PM

2017-09-27 Thread Manu Gautam
Disable clocks and dp/dm asynchronous interrupts from
PHY as part of runtime suspend.

Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qusb2.c | 159 ++
 1 file changed, 159 insertions(+)

diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c 
b/drivers/phy/qualcomm/phy-qcom-qusb2.c
index 0e9d88b..7414272 100644
--- a/drivers/phy/qualcomm/phy-qcom-qusb2.c
+++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c
@@ -56,6 +56,18 @@
 
 #define PHY_CLK_SCHEME_SEL BIT(0)
 
+/* QUSB2PHY_INTR_CTRL register bits */
+#define DMSE_INTR_HIGH_SEL BIT(4)
+#define DPSE_INTR_HIGH_SEL BIT(3)
+#define CHG_DET_INTR_ENBIT(2)
+#define DMSE_INTR_EN   BIT(1)
+#define DPSE_INTR_EN   BIT(0)
+
+/* QUSB2PHY_PLL_CORE_INPUT_OVERRIDE register bits */
+#define CORE_PLL_EN_FROM_RESET BIT(4)
+#define CORE_RESET BIT(5)
+#define CORE_RESET_MUX BIT(6)
+
 #defineQUSB2PHY_PLL_ANALOG_CONTROLS_TWO0x04
 #defineQUSB2PHY_PLL_CLOCK_INVERTERS0x18c
 #defineQUSB2PHY_PLL_CMODE  0x2c
@@ -73,6 +85,10 @@
 #define UTMI_OTG_VBUS_VALIDBIT(20)
 #define SW_SESSVLD_SEL BIT(28)
 
+#define QSCRATCH_CHARGING_DET_OUTPUT   0x1C
+#define LINESTATE_DP   BIT(8)
+#define LINESTATE_DM   BIT(9)
+
 struct qusb2_phy_init_tbl {
unsigned int offset;
unsigned int val;
@@ -98,6 +114,7 @@ struct qusb2_phy_init_tbl {
 
 /* set of registers with offsets different per-PHY */
 enum qusb2phy_reg_layout {
+   QUSB2PHY_PLL_CORE_INPUT_OVERRIDE,
QUSB2PHY_PLL_STATUS,
QUSB2PHY_PORT_TUNE1,
QUSB2PHY_PORT_TUNE2,
@@ -117,8 +134,10 @@ enum qusb2phy_reg_layout {
[QUSB2PHY_PORT_TUNE3]   = 0x88,
[QUSB2PHY_PORT_TUNE4]   = 0x8c,
[QUSB2PHY_PORT_TUNE5]   = 0x90,
+   [QUSB2PHY_PORT_TEST1]   = 0xb8,
[QUSB2PHY_PORT_TEST2]   = 0x9c,
[QUSB2PHY_PORT_POWERDOWN]   = 0xb4,
+   [QUSB2PHY_INTR_CTRL]= 0xbc,
 };
 
 static const struct qusb2_phy_init_tbl msm8996_init_tbl[] = {
@@ -138,14 +157,17 @@ enum qusb2phy_reg_layout {
 };
 
 static const unsigned int qusb2_v2_regs_layout[] = {
+   [QUSB2PHY_PLL_CORE_INPUT_OVERRIDE] = 0xa8,
[QUSB2PHY_PLL_STATUS]   = 0x1a0,
[QUSB2PHY_PORT_TUNE1]   = 0x240,
[QUSB2PHY_PORT_TUNE2]   = 0x244,
[QUSB2PHY_PORT_TUNE3]   = 0x248,
[QUSB2PHY_PORT_TUNE4]   = 0x24c,
[QUSB2PHY_PORT_TUNE5]   = 0x250,
+   [QUSB2PHY_PORT_TEST1]   = 0x254,
[QUSB2PHY_PORT_TEST2]   = 0x258,
[QUSB2PHY_PORT_POWERDOWN]   = 0x210,
+   [QUSB2PHY_INTR_CTRL]= 0x230,
 };
 
 static const struct qusb2_phy_init_tbl qusb2_v2_init_tbl[] = {
@@ -180,9 +202,13 @@ struct qusb2_phy_cfg {
const unsigned int *regs;
unsigned int mask_core_ready;
unsigned int disable_ctrl;
+   unsigned int autoresume_en;
 
/* true if PHY has PLL_TEST register to select clk_scheme */
bool has_pll_test;
+
+   /* true if PHY has PLL_CORE_INPUT_OVERRIDE register to reset PLL */
+   bool has_pll_override;
 };
 
 static const struct qusb2_phy_cfg msm8996_phy_cfg = {
@@ -193,6 +219,7 @@ struct qusb2_phy_cfg {
.has_pll_test   = true,
.disable_ctrl   = (CLAMP_N_EN | FREEZIO_N | POWER_DOWN),
.mask_core_ready = PLL_LOCKED,
+   .autoresume_en   = BIT(3),
 };
 
 static const struct qusb2_phy_cfg qusb2_v2_phy_cfg = {
@@ -203,6 +230,8 @@ struct qusb2_phy_cfg {
.disable_ctrl   = (PWR_CTRL1_VREF_SUPPLY_TRIM | PWR_CTRL1_CLAMP_N_EN |
   POWER_DOWN),
.mask_core_ready = CORE_READY_STATUS,
+   .has_pll_override = true,
+   .autoresume_en= BIT(0),
 };
 
 static const char * const qusb2_phy_vreg_names[] = {
@@ -229,6 +258,7 @@ struct qusb2_phy_cfg {
  *
  * @cfg: phy config data
  * @has_se_clk_scheme: indicate if PHY has single-ended ref clock scheme
+ * @phy_initialized: indicate if PHY has been initialized
  * @mode: indicate current PHY mode of operation e.g. HOST or DEVICE
  */
 struct qusb2_phy {
@@ -247,6 +277,7 @@ struct qusb2_phy {
 
const struct qusb2_phy_cfg *cfg;
bool has_se_clk_scheme;
+   bool phy_initialized;
enum phy_mode mode;
 };
 
@@ -335,6 +366,115 @@ static int qusb2_phy_set_mode(struct phy *phy, enum 
phy_mode mode)
return 0;
 }
 
+static int __maybe_unused qusb2_phy_runtime_suspend(struct device *dev)
+{
+   struct qusb2_phy *qphy = dev_get_drvdata(dev);
+   const struct qusb2_phy_cfg *cfg = qphy->cfg;
+   u32 linestate = 0, intr_mask;
+
+   dev_vdbg(dev, "Suspending QUSB2 Phy,

[PATCH v2 17/17] phy: qcom-qmp: Add support for runtime PM

2017-09-27 Thread Manu Gautam
Disable clocks as part of PHY suspend. This also requires enabling
PHY autonomous mode to detect lfps/rx_det in suspend state.

Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qmp.c | 182 +++-
 drivers/phy/qualcomm/phy-qcom-qmp.h |   3 +
 2 files changed, 184 insertions(+), 1 deletion(-)

diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c 
b/drivers/phy/qualcomm/phy-qcom-qmp.c
index 1403de3..a04ba28 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.c
@@ -61,6 +61,20 @@
 #define USB3_MODE  BIT(0) /* enables USB3 mode */
 #define DP_MODEBIT(1) /* enables DP 
mode */
 
+/* QPHY_PCS_AUTONOMOUS_MODE_CTRL register bits */
+#define ARCVR_DTCT_EN  BIT(0)
+#define ALFPS_DTCT_EN  BIT(1)
+#define ARCVR_DTCT_EVENT_SEL   BIT(4)
+
+/* QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR register bits */
+#define IRQ_CLEAR  BIT(0)
+
+/* QPHY_PCS_LFPS_RXTERM_IRQ_STATUS register bits */
+#define RCVR_DETECTBIT(0)
+
+/* QPHY_V3_PCS_MISC_CLAMP_ENABLE register bits */
+#define CLAMP_EN   BIT(0) /* enables i/o clamp_n */
+
 /* QSCRATCH register bits */
 #define QSCRATCH_SS_PHY_CTRL   0x30
 #define LANE0_PWR_PRESENT  BIT(24)
@@ -111,6 +125,9 @@ enum qphy_reg_layout {
QPHY_SW_RESET,
QPHY_START_CTRL,
QPHY_PCS_READY_STATUS,
+   QPHY_PCS_AUTONOMOUS_MODE_CTRL,
+   QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR,
+   QPHY_PCS_LFPS_RXTERM_IRQ_STATUS,
 };
 
 static const unsigned int pciephy_regs_layout[] = {
@@ -138,12 +155,18 @@ enum qphy_reg_layout {
[QPHY_SW_RESET] = 0x00,
[QPHY_START_CTRL]   = 0x08,
[QPHY_PCS_READY_STATUS] = 0x17c,
+   [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = 0x0d4,
+   [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR]  = 0x0d8,
+   [QPHY_PCS_LFPS_RXTERM_IRQ_STATUS] = 0x178,
 };
 
 static const unsigned int qmp_v3_usb3phy_regs_layout[] = {
[QPHY_SW_RESET] = 0x00,
[QPHY_START_CTRL]   = 0x08,
[QPHY_PCS_READY_STATUS] = 0x174,
+   [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = 0x0d8,
+   [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR]  = 0x0dc,
+   [QPHY_PCS_LFPS_RXTERM_IRQ_STATUS] = 0x170,
 };
 
 static const struct qmp_phy_init_tbl msm8996_pcie_serdes_tbl[] = {
@@ -539,6 +562,7 @@ struct qmp_phy_cfg {
  * @tx: iomapped memory space for lane's tx
  * @rx: iomapped memory space for lane's rx
  * @pcs: iomapped memory space for lane's pcs
+ * @pcs_misc: iomapped memory space for lane's pcs_misc
  * @pipe_clk: pipe lock
  * @index: lane index
  * @qmp: QMP phy to which this lane belongs
@@ -549,6 +573,7 @@ struct qmp_phy {
void __iomem *tx;
void __iomem *rx;
void __iomem *pcs;
+   void __iomem *pcs_misc;
struct clk *pipe_clk;
unsigned int index;
struct qcom_qmp *qmp;
@@ -587,6 +612,7 @@ struct qcom_qmp {
 
struct mutex phy_mutex;
int init_count;
+   bool phy_initialized;
enum phy_mode mode;
 };
 
@@ -784,6 +810,7 @@ static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
 {
const struct qmp_phy_cfg *cfg = qmp->cfg;
void __iomem *serdes = qmp->serdes;
+   void __iomem *dp_com = qmp->dp_com;
int ret, i;
 
mutex_lock(&qmp->phy_mutex);
@@ -993,6 +1020,7 @@ static int qcom_qmp_phy_init(struct phy *phy)
dev_err(qmp->dev, "pipe_clk enable failed, err=%d\n", ret);
goto err_pcs_ready;
}
+   qmp->phy_initialized = true;
 
return 0;
 
@@ -1027,6 +1055,135 @@ static int qcom_qmp_phy_exit(struct phy *phy)
 
qcom_qmp_phy_com_exit(qmp);
 
+   qmp->phy_initialized = false;
+
+   return 0;
+}
+
+static void qcom_qmp_phy_enable_autonomous_mode(struct qmp_phy *qphy)
+{
+   struct qcom_qmp *qmp = qphy->qmp;
+   const struct qmp_phy_cfg *cfg = qmp->cfg;
+   void __iomem *pcs = qphy->pcs;
+   void __iomem *pcs_misc = qphy->pcs_misc;
+   unsigned int reg;
+
+   /* Clear previous PHY int_status before checking rx_det */
+   qphy_setbits(pcs, cfg->regs[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR], IRQ_CLEAR);
+   /* Writing 1 followed by 0 clears the interrupt */
+   qphy_clrbits(pcs, cfg->regs[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR], IRQ_CLEAR);
+
+   /* Enable PHY autonomous mode to detect lfps and rx_det detach */
+   qphy_setbits(pcs, cfg->regs[QPHY_PCS_AUTONOMOUS_MODE_CTRL],
+ARCVR_DTCT_EN | ALFPS_DTCT_EN);
+
+   /* Enable i/o clamp_n for autonomous mode */
+   if (pcs_misc)
+   qphy_clrbits(pcs_misc, QPHY_V3_PCS_MISC_CLAMP_ENABLE, CLAMP_EN);
+
+   /* Add delay for int_status to reflect current rx_de

[PATCH v2 14/17] phy: qcom-qusb2: Set vbus sw-override signal in device mode

2017-09-27 Thread Manu Gautam
VBUS signal coming from PHY must be asserted in device for
controller to start operation or assert pull-up. For some
platforms where VBUS line is not connected to PHY there is
HS_PHY_CTRL register in QSCRATCH wrapper that can be used
by software to override VBUS signal going to controller.

Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qusb2.c | 39 +++
 1 file changed, 39 insertions(+)

diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c 
b/drivers/phy/qualcomm/phy-qcom-qusb2.c
index bda1f4c..0e9d88b 100644
--- a/drivers/phy/qualcomm/phy-qcom-qusb2.c
+++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c
@@ -68,6 +68,11 @@
 #defineQUSB2PHY_IMP_CTRL2  0x224
 #defineQUSB2PHY_CHG_CTRL2  0x23c
 
+/* QSCRATCH register bits */
+#define QSCRATCH_HS_PHY_CTRL   0x10
+#define UTMI_OTG_VBUS_VALIDBIT(20)
+#define SW_SESSVLD_SEL BIT(28)
+
 struct qusb2_phy_init_tbl {
unsigned int offset;
unsigned int val;
@@ -211,6 +216,7 @@ struct qusb2_phy_cfg {
  *
  * @phy: generic phy
  * @base: iomapped memory space for qubs2 phy
+ * @qscratch_base: iomapped memory space for qscratch region
  *
  * @cfg_ahb_clk: AHB2PHY interface clock
  * @ref_clk: phy reference clock
@@ -223,10 +229,12 @@ struct qusb2_phy_cfg {
  *
  * @cfg: phy config data
  * @has_se_clk_scheme: indicate if PHY has single-ended ref clock scheme
+ * @mode: indicate current PHY mode of operation e.g. HOST or DEVICE
  */
 struct qusb2_phy {
struct phy *phy;
void __iomem *base;
+   void __iomem *qscratch_base;
 
struct clk *cfg_ahb_clk;
struct clk *ref_clk;
@@ -239,6 +247,7 @@ struct qusb2_phy {
 
const struct qusb2_phy_cfg *cfg;
bool has_se_clk_scheme;
+   enum phy_mode mode;
 };
 
 static inline void qusb2_setbits(void __iomem *base, u32 offset, u32 val)
@@ -307,6 +316,25 @@ static void qusb2_phy_set_tune2_param(struct qusb2_phy 
*qphy)
qusb2_setbits(qphy->base, QUSB2PHY_PORT_TUNE2, val[0] << 0x4);
 }
 
+static int qusb2_phy_set_mode(struct phy *phy, enum phy_mode mode)
+{
+   struct qusb2_phy *qphy = phy_get_drvdata(phy);
+
+   qphy->mode = mode;
+
+   /* Update VBUS override in qscratch register */
+   if (qphy->qscratch_base) {
+   if (mode == PHY_MODE_USB_DEVICE)
+   qusb2_setbits(qphy->qscratch_base, QSCRATCH_HS_PHY_CTRL,
+ UTMI_OTG_VBUS_VALID | SW_SESSVLD_SEL);
+   else
+   qusb2_clrbits(qphy->qscratch_base, QSCRATCH_HS_PHY_CTRL,
+ UTMI_OTG_VBUS_VALID | SW_SESSVLD_SEL);
+   }
+
+   return 0;
+}
+
 static int qusb2_phy_init(struct phy *phy)
 {
struct qusb2_phy *qphy = phy_get_drvdata(phy);
@@ -473,6 +501,7 @@ static int qusb2_phy_exit(struct phy *phy)
 static const struct phy_ops qusb2_phy_gen_ops = {
.init   = qusb2_phy_init,
.exit   = qusb2_phy_exit,
+   .set_mode   = qusb2_phy_set_mode,
.owner  = THIS_MODULE,
 };
 
@@ -507,6 +536,16 @@ static int qusb2_phy_probe(struct platform_device *pdev)
if (IS_ERR(qphy->base))
return PTR_ERR(qphy->base);
 
+   /* Check if platform uses qscratch wrapper */
+   res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qscratch");
+   if (res) {
+   /* Can't request region as used by other phy and glue drivers */
+   qphy->qscratch_base = devm_ioremap(dev, res->start,
+  resource_size(res));
+   if (IS_ERR(qphy->qscratch_base))
+   return PTR_ERR(qphy->qscratch_base);
+   }
+
qphy->cfg_ahb_clk = devm_clk_get(dev, "cfg_ahb");
if (IS_ERR(qphy->cfg_ahb_clk)) {
ret = PTR_ERR(qphy->cfg_ahb_clk);
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v2 10/17] phy: qcom-qmp: Move register offsets to header file

2017-09-27 Thread Manu Gautam
New revision (v3) of QMP PHY uses different offsets
for almost all of the registers. Hence, move these
definitions to header file so that updated offsets
can be added for QMP v3.

Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qmp.c | 119 +--
 drivers/phy/qualcomm/phy-qcom-qmp.h | 137 
 2 files changed, 138 insertions(+), 118 deletions(-)
 create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp.h

diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c 
b/drivers/phy/qualcomm/phy-qcom-qmp.c
index 263cf50..15a734f 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.c
@@ -31,124 +31,7 @@
 
 #include 
 
-/* QMP PHY QSERDES COM registers */
-#define QSERDES_COM_BG_TIMER   0x00c
-#define QSERDES_COM_SSC_EN_CENTER  0x010
-#define QSERDES_COM_SSC_ADJ_PER1   0x014
-#define QSERDES_COM_SSC_ADJ_PER2   0x018
-#define QSERDES_COM_SSC_PER1   0x01c
-#define QSERDES_COM_SSC_PER2   0x020
-#define QSERDES_COM_SSC_STEP_SIZE1 0x024
-#define QSERDES_COM_SSC_STEP_SIZE2 0x028
-#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN0x034
-#define QSERDES_COM_CLK_ENABLE10x038
-#define QSERDES_COM_SYS_CLK_CTRL   0x03c
-#define QSERDES_COM_SYSCLK_BUF_ENABLE  0x040
-#define QSERDES_COM_PLL_IVCO   0x048
-#define QSERDES_COM_LOCK_CMP1_MODE00x04c
-#define QSERDES_COM_LOCK_CMP2_MODE00x050
-#define QSERDES_COM_LOCK_CMP3_MODE00x054
-#define QSERDES_COM_LOCK_CMP1_MODE10x058
-#define QSERDES_COM_LOCK_CMP2_MODE10x05c
-#define QSERDES_COM_LOCK_CMP3_MODE10x060
-#define QSERDES_COM_BG_TRIM0x070
-#define QSERDES_COM_CLK_EP_DIV 0x074
-#define QSERDES_COM_CP_CTRL_MODE0  0x078
-#define QSERDES_COM_CP_CTRL_MODE1  0x07c
-#define QSERDES_COM_PLL_RCTRL_MODE00x084
-#define QSERDES_COM_PLL_RCTRL_MODE10x088
-#define QSERDES_COM_PLL_CCTRL_MODE00x090
-#define QSERDES_COM_PLL_CCTRL_MODE10x094
-#define QSERDES_COM_BIAS_EN_CTRL_BY_PSM0x0a8
-#define QSERDES_COM_SYSCLK_EN_SEL  0x0ac
-#define QSERDES_COM_RESETSM_CNTRL  0x0b4
-#define QSERDES_COM_RESTRIM_CTRL   0x0bc
-#define QSERDES_COM_RESCODE_DIV_NUM0x0c4
-#define QSERDES_COM_LOCK_CMP_EN0x0c8
-#define QSERDES_COM_LOCK_CMP_CFG   0x0cc
-#define QSERDES_COM_DEC_START_MODE00x0d0
-#define QSERDES_COM_DEC_START_MODE10x0d4
-#define QSERDES_COM_DIV_FRAC_START1_MODE0  0x0dc
-#define QSERDES_COM_DIV_FRAC_START2_MODE0  0x0e0
-#define QSERDES_COM_DIV_FRAC_START3_MODE0  0x0e4
-#define QSERDES_COM_DIV_FRAC_START1_MODE1  0x0e8
-#define QSERDES_COM_DIV_FRAC_START2_MODE1  0x0ec
-#define QSERDES_COM_DIV_FRAC_START3_MODE1  0x0f0
-#define QSERDES_COM_INTEGLOOP_GAIN0_MODE0  0x108
-#define QSERDES_COM_INTEGLOOP_GAIN1_MODE0  0x10c
-#define QSERDES_COM_INTEGLOOP_GAIN0_MODE1  0x110
-#define QSERDES_COM_INTEGLOOP_GAIN1_MODE1  0x114
-#define QSERDES_COM_VCO_TUNE_CTRL  0x124
-#define QSERDES_COM_VCO_TUNE_MAP   0x128
-#define QSERDES_COM_VCO_TUNE1_MODE00x12c
-#define QSERDES_COM_VCO_TUNE2_MODE00x130
-#define QSERDES_COM_VCO_TUNE1_MODE10x134
-#define QSERDES_COM_VCO_TUNE2_MODE10x138
-#define QSERDES_COM_VCO_TUNE_TIMER10x144
-#define QSERDES_COM_VCO_TUNE_TIMER20x148
-#define QSERDES_COM_BG_CTRL0x170
-#define QSERDES_COM_CLK_SELECT 0x174
-#define QSERDES_COM_HSCLK_SEL  0x178
-#define QSERDES_COM_CORECLK_DIV0x184
-#define QSERDES_COM_CORE_CLK_EN0x18c
-#define QSERDES_COM_C_READY_STATUS 0x190
-#define QSERDES_COM_CMN_CONFIG 0x194
-#define QSERDES_COM_SVS_MODE_CLK_SEL   0x19c
-#define QSERDES_COM_DEBUG_BUS0 0x1a0
-#define QSERDES_COM_DEBUG_BUS1 0x1a4
-#define QSERDES_COM_DEBUG_BUS2 0x1a8
-#define QSERDES_COM_DEBUG_BUS3 0x1ac
-#define QSERDES_COM_DEBUG_BUS_SEL  0x1b0
-#define QSERDES_COM_CORECLK_DIV_MODE1

[PATCH v2 11/17] phy: qcom-qmp: Add register offsets for QMP V3 PHY

2017-09-27 Thread Manu Gautam
Registers offsets for QMP V3 PHY are changed from
previous versions (1/2), update same in header file.

Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qmp.h | 149 
 1 file changed, 149 insertions(+)

diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.h 
b/drivers/phy/qualcomm/phy-qcom-qmp.h
index d930ca7..f7d4c2a 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.h
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.h
@@ -134,4 +134,153 @@
 #define QPHY_L1SS_WAKEUP_DLY_TIME_AUXCLK_LSB   0x1DC
 #define QPHY_L1SS_WAKEUP_DLY_TIME_AUXCLK_MSB   0x1E0
 
+/* Only for QMP V3 PHY - DP COM registers */
+#define QPHY_V3_DP_COM_PHY_MODE_CTRL   0x00
+#define QPHY_V3_DP_COM_SW_RESET0x04
+#define QPHY_V3_DP_COM_POWER_DOWN_CTRL 0x08
+#define QPHY_V3_DP_COM_SWI_CTRL0x0c
+#define QPHY_V3_DP_COM_TYPEC_CTRL  0x10
+#define QPHY_V3_DP_COM_TYPEC_PWRDN_CTRL0x14
+#define QPHY_V3_DP_COM_RESET_OVRD_CTRL 0x1c
+
+/* Only for QMP V3 PHY - QSERDES COM registers */
+#define QSERDES_V3_COM_BG_TIMER0x00c
+#define QSERDES_V3_COM_SSC_EN_CENTER   0x010
+#define QSERDES_V3_COM_SSC_ADJ_PER10x014
+#define QSERDES_V3_COM_SSC_ADJ_PER20x018
+#define QSERDES_V3_COM_SSC_PER10x01c
+#define QSERDES_V3_COM_SSC_PER20x020
+#define QSERDES_V3_COM_SSC_STEP_SIZE1  0x024
+#define QSERDES_V3_COM_SSC_STEP_SIZE2  0x028
+#define QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN 0x034
+#define QSERDES_V3_COM_CLK_ENABLE1 0x038
+#define QSERDES_V3_COM_SYS_CLK_CTRL0x03c
+#define QSERDES_V3_COM_SYSCLK_BUF_ENABLE   0x040
+#define QSERDES_V3_COM_PLL_IVCO0x048
+#define QSERDES_V3_COM_LOCK_CMP1_MODE0 0x098
+#define QSERDES_V3_COM_LOCK_CMP2_MODE0 0x09c
+#define QSERDES_V3_COM_LOCK_CMP3_MODE0 0x0a0
+#define QSERDES_V3_COM_LOCK_CMP1_MODE1 0x0a4
+#define QSERDES_V3_COM_LOCK_CMP2_MODE1 0x0a8
+#define QSERDES_V3_COM_LOCK_CMP3_MODE1 0x0ac
+#define QSERDES_V3_COM_CLK_EP_DIV  0x05c
+#define QSERDES_V3_COM_CP_CTRL_MODE0   0x060
+#define QSERDES_V3_COM_CP_CTRL_MODE1   0x064
+#define QSERDES_V3_COM_PLL_RCTRL_MODE0 0x068
+#define QSERDES_V3_COM_PLL_RCTRL_MODE1 0x06c
+#define QSERDES_V3_COM_PLL_CCTRL_MODE0 0x070
+#define QSERDES_V3_COM_PLL_CCTRL_MODE1 0x074
+#define QSERDES_V3_COM_SYSCLK_EN_SEL   0x080
+#define QSERDES_V3_COM_RESETSM_CNTRL   0x088
+#define QSERDES_V3_COM_RESETSM_CNTRL2  0x08c
+#define QSERDES_V3_COM_LOCK_CMP_EN 0x090
+#define QSERDES_V3_COM_LOCK_CMP_CFG0x094
+#define QSERDES_V3_COM_DEC_START_MODE0 0x0b0
+#define QSERDES_V3_COM_DEC_START_MODE1 0x0b4
+#define QSERDES_V3_COM_DIV_FRAC_START1_MODE0   0x0b8
+#define QSERDES_V3_COM_DIV_FRAC_START2_MODE0   0x0bc
+#define QSERDES_V3_COM_DIV_FRAC_START3_MODE0   0x0c0
+#define QSERDES_V3_COM_DIV_FRAC_START1_MODE1   0x0c4
+#define QSERDES_V3_COM_DIV_FRAC_START2_MODE1   0x0c8
+#define QSERDES_V3_COM_DIV_FRAC_START3_MODE1   0x0cc
+#define QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE0   0x0d8
+#define QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE0   0x0dc
+#define QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE1   0x0e0
+#define QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE1   0x0e4
+#define QSERDES_V3_COM_VCO_TUNE_CTRL   0x0ec
+#define QSERDES_V3_COM_VCO_TUNE_MAP0x0f0
+#define QSERDES_V3_COM_VCO_TUNE1_MODE0 0x0f4
+#define QSERDES_V3_COM_VCO_TUNE2_MODE0 0x0f8
+#define QSERDES_V3_COM_VCO_TUNE1_MODE1 0x0fc
+#define QSERDES_V3_COM_VCO_TUNE2_MODE1 0x100
+#define QSERDES_V3_COM_VCO_TUNE_TIMER1 0x11c
+#define QSERDES_V3_COM_VCO_TUNE_TIMER2 0x120
+#define QSERDES_V3_COM_CLK_SELECT  0x138
+#define QSERDES_V3_COM_HSCLK_SEL   0x13c
+#define QSERDES_V3_COM_CORECLK_DIV_MODE0   0x148
+#define QSERDES_V3_COM_CORECLK_DIV_MODE1   0x14c
+#define QSERDES_V3_COM_CORE_CLK_EN 0x154
+#define QSERDES_V3_COM_C_READY_STATUS  0x158
+#define QSERDES_V3_COM_CMN_CONFIG  0x15c
+#define QSERDES_V3_COM_SVS_MODE_CLK_SEL0x164
+#define QSERDES_V3_COM_DEBUG_BUS0  0x168
+#define QSERDES_V3_COM_DEBUG_BUS1  0x16c
+#define

[PATCH v2 08/17] dt-bindings: phy-qcom-qusb2: Update binding for QUSB2 V2 version

2017-09-27 Thread Manu Gautam
Update generic compatible string for QUSB2 V2 PHY. This will allow
all targets using QUSB2 V2 use same string.

Signed-off-by: Manu Gautam 
---
 Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt | 5 -
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt 
b/Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt
index aa0fcb0..42c9742 100644
--- a/Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt
+++ b/Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt
@@ -4,7 +4,10 @@ Qualcomm QUSB2 phy controller
 QUSB2 controller supports LS/FS/HS usb connectivity on Qualcomm chipsets.
 
 Required properties:
- - compatible: compatible list, contains "qcom,msm8996-qusb2-phy".
+ - compatible: compatible list, contains
+  "qcom,msm8996-qusb2-phy" for 14nm PHY on msm8996,
+  "qcom,qusb2-v2-phy" for QUSB2 V2 PHY.
+
  - reg: offset and length of the PHY register set.
  - #phy-cells: must be 0.
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[RESEND PATCH 3/3] usb: dwc3: core: Notify current USB mode to USB3 PHY as well

2017-09-27 Thread Manu Gautam
Driver currently notifies only USB2 PHY on USB mode change.
Extend this to USB3 PHY so that PHY drivers based on the
mode can release system resources - clocks, regulators etc.
Additionally Qualcomm QMP and QUSB2 PHY drivers need to
override VBUS signal in PHY wrapper in device mode as USB
VBUS line is not connected to PHYs. Also, remove NULL checks
for PHY when calling phy_set_mode as PHY ops already check this.

Signed-off-by: Manu Gautam 
---
 drivers/usb/dwc3/core.c | 17 -
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 23bb192..dabfa16 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -156,9 +156,8 @@ static void __dwc3_set_mode(struct work_struct *work)
} else {
if (dwc->usb2_phy)
otg_set_vbus(dwc->usb2_phy->otg, true);
-   if (dwc->usb2_generic_phy)
-   phy_set_mode(dwc->usb2_generic_phy, 
PHY_MODE_USB_HOST);
-
+   phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
+   phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST);
}
break;
case DWC3_GCTL_PRTCAP_DEVICE:
@@ -166,8 +165,8 @@ static void __dwc3_set_mode(struct work_struct *work)
 
if (dwc->usb2_phy)
otg_set_vbus(dwc->usb2_phy->otg, false);
-   if (dwc->usb2_generic_phy)
-   phy_set_mode(dwc->usb2_generic_phy, 
PHY_MODE_USB_DEVICE);
+   phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE);
+   phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE);
 
ret = dwc3_gadget_init(dwc);
if (ret)
@@ -932,8 +931,8 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
 
if (dwc->usb2_phy)
otg_set_vbus(dwc->usb2_phy->otg, false);
-   if (dwc->usb2_generic_phy)
-   phy_set_mode(dwc->usb2_generic_phy, 
PHY_MODE_USB_DEVICE);
+   phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE);
+   phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE);
 
ret = dwc3_gadget_init(dwc);
if (ret) {
@@ -948,8 +947,8 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
 
if (dwc->usb2_phy)
otg_set_vbus(dwc->usb2_phy->otg, true);
-   if (dwc->usb2_generic_phy)
-   phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
+   phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
+   phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST);
 
ret = dwc3_host_init(dwc);
if (ret) {
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[RESEND PATCH 1/3] usb: dwc3: Don't reinitialize core during host bus-suspend/resume

2017-09-27 Thread Manu Gautam
Driver powers-off PHYs and reinitializes DWC3 core and gadget on
resume. While this works fine for gadget mode but in host
mode there is not re-initialization of host stack. Also, resetting
bus as part of bus_suspend/resume is not correct which could affect
(or disconnect) connected devices.
Fix this by not reinitializing core on suspend/resume in host mode
for HOST only and OTG/drd configurations.

Signed-off-by: Manu Gautam 
---
 drivers/usb/dwc3/core.c | 43 ---
 1 file changed, 20 insertions(+), 23 deletions(-)

diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 03474d3..f75613f 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -927,6 +927,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
 
switch (dwc->dr_mode) {
case USB_DR_MODE_PERIPHERAL:
+   dwc->current_dr_role = DWC3_GCTL_PRTCAP_DEVICE;
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
 
if (dwc->usb2_phy)
@@ -942,6 +943,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
}
break;
case USB_DR_MODE_HOST:
+   dwc->current_dr_role = DWC3_GCTL_PRTCAP_HOST;
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
 
if (dwc->usb2_phy)
@@ -1293,21 +1295,19 @@ static int dwc3_suspend_common(struct dwc3 *dwc)
 {
unsigned long   flags;
 
-   switch (dwc->dr_mode) {
-   case USB_DR_MODE_PERIPHERAL:
-   case USB_DR_MODE_OTG:
+   switch (dwc->current_dr_role) {
+   case DWC3_GCTL_PRTCAP_DEVICE:
spin_lock_irqsave(&dwc->lock, flags);
dwc3_gadget_suspend(dwc);
spin_unlock_irqrestore(&dwc->lock, flags);
+   dwc3_core_exit(dwc);
break;
-   case USB_DR_MODE_HOST:
+   case DWC3_GCTL_PRTCAP_HOST:
default:
/* do nothing */
break;
}
 
-   dwc3_core_exit(dwc);
-
return 0;
 }
 
@@ -1316,18 +1316,17 @@ static int dwc3_resume_common(struct dwc3 *dwc)
unsigned long   flags;
int ret;
 
-   ret = dwc3_core_init(dwc);
-   if (ret)
-   return ret;
+   switch (dwc->current_dr_role) {
+   case DWC3_GCTL_PRTCAP_DEVICE:
+   ret = dwc3_core_init(dwc);
+   if (ret)
+   return ret;
 
-   switch (dwc->dr_mode) {
-   case USB_DR_MODE_PERIPHERAL:
-   case USB_DR_MODE_OTG:
spin_lock_irqsave(&dwc->lock, flags);
dwc3_gadget_resume(dwc);
spin_unlock_irqrestore(&dwc->lock, flags);
-   /* FALLTHROUGH */
-   case USB_DR_MODE_HOST:
+   break;
+   case DWC3_GCTL_PRTCAP_HOST:
default:
/* do nothing */
break;
@@ -1338,7 +1337,7 @@ static int dwc3_resume_common(struct dwc3 *dwc)
 
 static int dwc3_runtime_checks(struct dwc3 *dwc)
 {
-   switch (dwc->dr_mode) {
+   switch (dwc->current_dr_role) {
case USB_DR_MODE_PERIPHERAL:
case USB_DR_MODE_OTG:
if (dwc->connected)
@@ -1381,12 +1380,11 @@ static int dwc3_runtime_resume(struct device *dev)
if (ret)
return ret;
 
-   switch (dwc->dr_mode) {
-   case USB_DR_MODE_PERIPHERAL:
-   case USB_DR_MODE_OTG:
+   switch (dwc->current_dr_role) {
+   case DWC3_GCTL_PRTCAP_DEVICE:
dwc3_gadget_process_pending_events(dwc);
break;
-   case USB_DR_MODE_HOST:
+   case DWC3_GCTL_PRTCAP_HOST:
default:
/* do nothing */
break;
@@ -1402,13 +1400,12 @@ static int dwc3_runtime_idle(struct device *dev)
 {
struct dwc3 *dwc = dev_get_drvdata(dev);
 
-   switch (dwc->dr_mode) {
-   case USB_DR_MODE_PERIPHERAL:
-   case USB_DR_MODE_OTG:
+   switch (dwc->current_dr_role) {
+   case DWC3_GCTL_PRTCAP_DEVICE:
if (dwc3_runtime_checks(dwc))
return -EBUSY;
break;
-   case USB_DR_MODE_HOST:
+   case DWC3_GCTL_PRTCAP_HOST:
default:
/* do nothing */
break;
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[RESEND PATCH 2/3] usb: dwc3: pci: Runtime resume child device from wq

2017-09-27 Thread Manu Gautam
Driver currently resumes and increments pm usage_count
of its child device (dwc3 main) from its runtime_resume
handler. This requires dwc3 runtime_resume to perform
pm_runtime_put to decrement the pm usage_count. However
runtime_put from dwc3 happens for non pci drivers
(e.g. dwc3-if-simple.c) as well which results in dwc3
pm usage_count becoming negative after couple of
runtime suspend resume iterations. Fix this by
performing runtime_get/put from dwc3-pci driver only
using workqueue.

Signed-off-by: Manu Gautam 
---
 drivers/usb/dwc3/core.c |  1 -
 drivers/usb/dwc3/dwc3-pci.c | 29 +++--
 2 files changed, 27 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index f75613f..23bb192 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -1391,7 +1391,6 @@ static int dwc3_runtime_resume(struct device *dev)
}
 
pm_runtime_mark_last_busy(dev);
-   pm_runtime_put(dev);
 
return 0;
 }
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index 7e995df..74e4cd3 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -20,6 +20,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -61,6 +62,7 @@ struct dwc3_pci {
guid_t guid;
 
unsigned int has_dsm_for_pm:1;
+   struct work_struct wakeup_work;
 };
 
 static const struct acpi_gpio_params reset_gpios = { 0, 0, false };
@@ -174,6 +176,22 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc)
return 0;
 }
 
+#ifdef CONFIG_PM
+static void dwc3_pci_resume_work(struct work_struct *work)
+{
+   struct dwc3_pci *dwc = container_of(work, struct dwc3_pci, wakeup_work);
+   struct platform_device *dwc3 = dwc->dwc3;
+   int ret;
+
+   ret = pm_runtime_get_sync(&dwc3->dev);
+   if (ret)
+   return;
+
+   pm_runtime_mark_last_busy(&dwc3->dev);
+   pm_runtime_put_sync_autosuspend(&dwc3->dev);
+}
+#endif
+
 static int dwc3_pci_probe(struct pci_dev *pci,
const struct pci_device_id *id)
 {
@@ -232,6 +250,9 @@ static int dwc3_pci_probe(struct pci_dev *pci,
device_init_wakeup(dev, true);
pci_set_drvdata(pci, dwc);
pm_runtime_put(dev);
+#ifdef CONFIG_PM
+   INIT_WORK(&dwc->wakeup_work, dwc3_pci_resume_work);
+#endif
 
return 0;
 err:
@@ -243,6 +264,9 @@ static void dwc3_pci_remove(struct pci_dev *pci)
 {
struct dwc3_pci *dwc = pci_get_drvdata(pci);
 
+#ifdef CONFIG_PM
+   cancel_work_sync(&dwc->wakeup_work);
+#endif
device_init_wakeup(&pci->dev, false);
pm_runtime_get(&pci->dev);
platform_device_unregister(dwc->dwc3);
@@ -318,14 +342,15 @@ static int dwc3_pci_runtime_suspend(struct device *dev)
 static int dwc3_pci_runtime_resume(struct device *dev)
 {
struct dwc3_pci *dwc = dev_get_drvdata(dev);
-   struct platform_device  *dwc3 = dwc->dwc3;
int ret;
 
ret = dwc3_pci_dsm(dwc, PCI_INTEL_BXT_STATE_D0);
if (ret)
return ret;
 
-   return pm_runtime_get(&dwc3->dev);
+   queue_work(pm_wq, &dwc->wakeup_work);
+
+   return 0;
 }
 #endif /* CONFIG_PM */
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH v2 14/17] phy: qcom-qusb2: Set vbus sw-override signal in device mode

2017-09-27 Thread Manu Gautam
Hi Jack,


On 9/28/2017 12:46 AM, Jack Pham wrote:
> On Wed, Sep 27, 2017 at 10:57:41AM -0700, Jack Pham wrote:
>> Hi Manu,
>>
>> On Wed, Sep 27, 2017 at 02:29:10PM +0530, Manu Gautam wrote:
>>> VBUS signal coming from PHY must be asserted in device for
>>> controller to start operation or assert pull-up. For some
>>> platforms where VBUS line is not connected to PHY there is
>>> HS_PHY_CTRL register in QSCRATCH wrapper that can be used
>>> by software to override VBUS signal going to controller.
>>>
>>> Signed-off-by: Manu Gautam 
>>> ---
>>>  
>>> +static int qusb2_phy_set_mode(struct phy *phy, enum phy_mode mode)
>>> +{
>>> +   struct qusb2_phy *qphy = phy_get_drvdata(phy);
>>> +
>>> +   qphy->mode = mode;
>>> +
>>> +   /* Update VBUS override in qscratch register */
>>> +   if (qphy->qscratch_base) {
>>> +   if (mode == PHY_MODE_USB_DEVICE)
>>> +   qusb2_setbits(qphy->qscratch_base, QSCRATCH_HS_PHY_CTRL,
>>> + UTMI_OTG_VBUS_VALID | SW_SESSVLD_SEL);
>>> +   else
>>> +   qusb2_clrbits(qphy->qscratch_base, QSCRATCH_HS_PHY_CTRL,
>>> + UTMI_OTG_VBUS_VALID | SW_SESSVLD_SEL);
>> Wouldn't this be better off handled in the controller glue driver? Two
>> reasons I think this patch is unattractive:
>>
>> - qscratch_base is part of the controller's register space. Your later
>>   patch 16/17 ("phy: qcom-qmp: Override lane0_power_present signal in
>>   device mode") does a similar thing and hence both drivers have to
>>   ioremap() the same register resource while at the same time avoiding
>>   request_mem_region() (called by devm_ioremap_resource) to allow it to
>>   be mapped in both places.

Right. There is one more reason why qusb2 driver needs qscratch:
- During runtime suspend, it has to check linestate to set correct  polarity 
for dp/dm
  wakeup interrupt in order to detect disconnect/resume ion LS and FS/HS modes.

>> - VBUS override bit becomes asserted simply because the mode is changed
>>   to device mode but this is irrespective of the actual VBUS state. This
>>   could break some test setups which perform a logical disconnect by
>>   switching off/on VBUS while leaving data lines connected. Controller
>>   would go merrily along thinking it is still attached to the host.
>>
>> Instead maybe this could be tied to EXTCON_USB handling in the glue
>> driver; though it would need to be an additional notifier on top of
>> dwc3/drd.c which already handles extcon for host/device mode.

Yes, dwc3/drd.c currently deals with only EXTCON_USB_HOST. So, for platforms
where role swap happens using only Vbus or single GPIO this should take care of.


> That is to say, we'd probably need to split out dwc3-qcom from
> dwc3-of-simple.c into its own driver (again) in order to add this.
>
> Jack

However, I agree that more appropriate place for lane0-pwr-present and
vbus override update is dwc3 glue driver. Since we don't have one right now,

IMO once we have dwc3-qcom driver in place, this handling can be moved from
PHY to glue driver. Until then we can use this approach to get USB device mode
working on qcom platforms which are using dwc3-of-simple.c e.g. sdm820
dragonboard.


-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH v2 14/17] phy: qcom-qusb2: Set vbus sw-override signal in device mode

2017-10-09 Thread Manu Gautam
Hi Kishon

On 10/5/2017 2:38 PM, Manu Gautam wrote:
> Hi Jack,
>
> On 9/28/2017 10:23 PM, Jack Pham wrote:
>>
>>>>>> +static int qusb2_phy_set_mode(struct phy *phy, enum phy_mode mode)
>>>>>> +{
>>>>>> +struct qusb2_phy *qphy = phy_get_drvdata(phy);
>>>>>> +
>>>>>> +qphy->mode = mode;
>>>>>> +
>>>>>> +/* Update VBUS override in qscratch register */
>>>>>> +if (qphy->qscratch_base) {
>>>>>> +if (mode == PHY_MODE_USB_DEVICE)
>>>>>> +qusb2_setbits(qphy->qscratch_base, 
>>>>>> QSCRATCH_HS_PHY_CTRL,
>>>>>> +  UTMI_OTG_VBUS_VALID | 
>>>>>> SW_SESSVLD_SEL);
>>>>>> +else
>>>>>> +qusb2_clrbits(qphy->qscratch_base, 
>>>>>> QSCRATCH_HS_PHY_CTRL,
>>>>>> +  UTMI_OTG_VBUS_VALID | 
>>>>>> SW_SESSVLD_SEL);
>>>>> Wouldn't this be better off handled in the controller glue driver? Two
>>>>> reasons I think this patch is unattractive:
>>>>>
>>>>> - qscratch_base is part of the controller's register space. Your later
>>>>>   patch 16/17 ("phy: qcom-qmp: Override lane0_power_present signal in
>>>>>   device mode") does a similar thing and hence both drivers have to
>>>>>   ioremap() the same register resource while at the same time avoiding
>>>>>   request_mem_region() (called by devm_ioremap_resource) to allow it to
>>>>>   be mapped in both places.
>>> Right. There is one more reason why qusb2 driver needs qscratch:
>>> - During runtime suspend, it has to check linestate to set correct  
>>> polarity for dp/dm
>>>   wakeup interrupt in order to detect disconnect/resume ion LS and FS/HS 
>>> modes.
>> Ugh, oh yeah. The way I understand we did it in our downstream driver
>> is still to have the controller driver read the linestate but then pass
>> the information via additional set_mode() flags which the PHY driver
>> could use to correctly arm the interrupt trigger polarity.
>>
>> An alternative would be to access a couple of the debug QUSB2PHY
>> registers that also provide a reading of the current UTMI linestate. The
>> HPG mentions them vaguely, and I can't remember if we tested that
>> interface or not. Assuming it works, would that be preferable to reading
>> a non-PHY register here?
> it looks like newer QUSB2 PHY doesn't have a register to read linestate.
> QSCRATCH is the only option.
> However, setting dp/dm wakeup interrupt polarity based on current linestate
> isn't perfect either. It could race with any change in linestate while it was 
> being
> read, resulting in missed wakeup interrupt.
> Same is the case with QMP PHY when trying to check for RX terminations on
> suspend.
> IMO PHY driver should get this info from platform glue or controller driver.
> E.g. current speed -> SS, HS/FS, LS or NONE (if not in session).
>
> Kishon,
> What would you suggest here?
> Should we add new calls e.g. phy_get/set_current_speed like::
>
> diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h
> index 78bb0d7..41d9ec2 100644
> --- a/include/linux/phy/phy.h
> +++ b/include/linux/phy/phy.h
> @@ -29,6 +29,14 @@ enum phy_mode {
>     PHY_MODE_USB_OTG,
>  };
>
> +enum phy_speed {
> +   PHY_SPEED_INVALID,
> +   PHY_SPEED_USB_LS,
> +   PHY_SPEED_USB_FS_HS,
> +   PHY_SPEED_USB_SS,
> +};
> +
>  /**
>   * struct phy_ops - set of function pointers for performing phy operations
>   * @init: operation to be performed for initializing phy
> @@ -45,6 +53,7 @@ struct phy_ops {
>     int (*power_on)(struct phy *phy);
>     int (*power_off)(struct phy *phy);
>     int (*set_mode)(struct phy *phy, enum phy_mode mode);
> +   int (*set_speed)(struct phy *phy, enum phy_speed speed);
>     int (*reset)(struct phy *phy);
>     struct module *owner;
>  };
>

@Kishon,
Let me know if we can add set_speed to phy_ops. We need this for glue
driver to notify PHY of current connection speed to enable appropriate
wakeup interrupts.


-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH] usb: dwc3: Support the dwc3 host suspend/resume

2017-07-24 Thread Manu Gautam
Hi Baolin,


On 7/24/2017 11:26 AM, Baolin Wang wrote:

 Other than what I pushed in my patch -
 ("usb: dwc3: Don't reinitialize core during host bus-suspend/resume")
 Just performing pm_request_resume or handling same in dwc3 glue
 driver should be sufficient.
>>> Yes.
>>>
 Also, what is trigger for runtime_resume for your platform?
>>> In our platform glue layer, we have extcon events to notify there are
>>> devices connected, then gule layer will resume dwc3 device.
>>>
>> IMO you can just perform resume of &dwc->xhci->dev instead of resuming dwc3.
>> Since, dwc3 is parent of xhci that will trigger resume of dwc3 as well.
> I am not sure this is good enough but it seems can solve some
> problems, then we do not need resume/suspend host in dwc3 core.

In that case can we proceed with this patch:
[1] https://www.spinics.net/lists/linux-usb/msg158682.html

For your platform you can pick this patch and resume dwc->xhci->dev resume
from your glue driver.
Do you have any other concerns?




Re: [PATCH] usb: dwc3: Support the dwc3 host suspend/resume

2017-07-24 Thread Manu Gautam
Hi,


On 7/24/2017 2:45 PM, Baolin Wang wrote:
> Hi Manu,
>
> On 24 July 2017 at 16:42, Manu Gautam  wrote:
>> Hi Baolin,
>>
>>
>> On 7/24/2017 11:26 AM, Baolin Wang wrote:
>>
>>>>>> Other than what I pushed in my patch -
>>>>>> ("usb: dwc3: Don't reinitialize core during host bus-suspend/resume")
>>>>>> Just performing pm_request_resume or handling same in dwc3 glue
>>>>>> driver should be sufficient.
>>>>> Yes.
>>>>>
>>>>>> Also, what is trigger for runtime_resume for your platform?
>>>>> In our platform glue layer, we have extcon events to notify there are
>>>>> devices connected, then gule layer will resume dwc3 device.
>>>>>
>>>> IMO you can just perform resume of &dwc->xhci->dev instead of resuming 
>>>> dwc3.
>>>> Since, dwc3 is parent of xhci that will trigger resume of dwc3 as well.
>>> I am not sure this is good enough but it seems can solve some
>>> problems, then we do not need resume/suspend host in dwc3 core.
>> In that case can we proceed with this patch:
>> [1] https://www.spinics.net/lists/linux-usb/msg158682.html
>>
>> For your platform you can pick this patch and resume dwc->xhci->dev resume
>> from your glue driver.
>> Do you have any other concerns?
> The same concern I explained in your patch. If we power off the
> controller when suspend, how can controller work well as host if we do
> not issue dwc3_core_init()? Suppose below cases:
> device attached: resume glue layer (power on dwc3 controller) --->
> resume dwc3 device ---> resume xHCI device
Just resume won't do. XHCI also needs to be reinitialized.

> no device attached: suspend xHCI device ---> suspend dwc3 device --->
> suspend glue layer (we can power off the dwc3 controller now)
>
> Though now there are no upstreamed glue drivers will power off dwc3
> controller, should we consider this situation?
>

Can we discuss on that patch thread itself?

How will this platform handle runtime PM with only external HUB
connected? Will runtime suspend take place?
Would connecting device to that HUB's port be detected?

Since, there is no upstreamed glue driver currently doing, we can
probably ignore that. Also, above sequnence wont work without xhci init.

Also, for this particular case glue driver can take care of re-initializing of
dwc3 core as well.



Re: [PATCH v1 1/6] phy: qcom-qmp: Fix phy pipe clock gating

2017-07-24 Thread Manu Gautam


On 7/21/2017 10:29 PM, Stephen Boyd wrote:
> On 07/21/2017 04:01 AM, Manu Gautam wrote:
>> From: Vivek Gautam 
>>
>> Pipe clock comes out of the phy and is available as long as
>> the phy is turned on. Clock controller fails to gate this
>> clock after the phy is turned off and generates a warning.
>>
>> / # [   33.048561] gcc_usb3_phy_pipe_clk status stuck at 'on'
>> [   33.048585] [ cut here ]
>> [   33.052621] WARNING: CPU: 1 PID: 18 at 
>> ../drivers/clk/qcom/clk-branch.c:97 clk_branch_wait+0xf0/0x108
>> [   33.057384] Modules linked in:
>> [   33.066497] CPU: 1 PID: 18 Comm: kworker/1:0 Tainted: GW   
>> 4.12.0-rc7-00024-gfe926e34c36d-dirty #96
>> [   33.069451] Hardware name: Qualcomm Technologies, Inc. DB820c (DT)
>> ...
>> [   33.278565] [] clk_branch_wait+0xf0/0x108
>> [   33.286375] [] clk_branch2_disable+0x28/0x34
>> [   33.291761] [] clk_core_disable+0x5c/0x88
>> [   33.297660] [] clk_core_disable_lock+0x20/0x34
>> [   33.303129] [] clk_disable+0x1c/0x24
>> [   33.309384] [] qcom_qmp_phy_poweroff+0x20/0x48
>> [   33.314328] [] phy_power_off+0x80/0xdc
>> [   33.320492] [] dwc3_core_exit+0x94/0xa0
>> [   33.325784] [] dwc3_suspend_common+0x50/0x60
>> [   33.331080] [] dwc3_runtime_suspend+0x48/0x6c
>> [   33.336810] [] pm_generic_runtime_suspend+0x28/0x38
>> [   33.342627] [] __rpm_callback+0x150/0x254
>> [   33.349222] [] rpm_callback+0x24/0x78
>> [   33.354604] [] rpm_suspend+0xe0/0x4e4
>> [   33.359813] [] pm_runtime_work+0xdc/0xf0
>> [   33.365028] [] process_one_work+0x12c/0x28c
>> [   33.370576] [] worker_thread+0x58/0x3b8
>> [   33.376393] [] kthread+0x100/0x12c
>> [   33.381776] [] ret_from_fork+0x10/0x50
>>
>> Fix this by enabling pipe clock at the end of phy_init(), and disabling
>> it as the first thing in phy_exit().
>>
>> Fixes: e78f3d15e115 ("phy: qcom-qmp: new qmp phy driver for qcom-chipsets")
>>
>> Signed-off-by: Vivek Gautam 
> Missing your signoff? Also, the fixes tag should be right before signoff
> without a newline between.
>

Will fix it in next version.



Re: [PATCH v1 6/6] usb: dwc3: core: Notify USB3 PHY as well for DRD modes

2017-07-24 Thread Manu Gautam


On 7/21/2017 10:39 PM, Stephen Boyd wrote:
> On 07/21/2017 04:02 AM, Manu Gautam wrote:
>> Driver currently notifies only USB3 PHY for mode change.
>> Extend this to USB3 PHY so that driver based on the mode
>> can release system resources - clocks, regulators etc.
>> and can even turn off PHY during runtime suspend.
>>
>> Signed-off-by: Manu Gautam 
> This patch is confusing because you say "notify for usb3 phy", but then
> combine a change to remove the NULL pointer check on phy_set_mode() for
> the usb2 phy. Please describe everything that's happening in a patch in
> the commit text.

Sure, will add a comment for that.
It was done to align with other phy_ops usage in the driver. Also, these
wrapper functions already have a NULL pointer check.




Re: [PATCH v1 4/6] phy: qcom-qusb2: Add support for runtime PM

2017-07-24 Thread Manu Gautam
Hi,


On 7/21/2017 10:54 PM, Stephen Boyd wrote:
> On 07/21/2017 04:01 AM, Manu Gautam wrote:
>> Driver can turn off clocks during runtime suspend.
>> Also, runtime suspend is not as a result of host mode
>> selective suspend then PHY can be powered off as well.
>>
>> Signed-off-by: Manu Gautam 
>>
>> diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c 
>> b/drivers/phy/qualcomm/phy-qcom-qusb2.c
>> index fa60a99..b505681 100644
>> --- a/drivers/phy/qualcomm/phy-qcom-qusb2.c
>> +++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c
>> @@ -132,6 +132,9 @@ struct qusb2_phy {
>>  
>>  const struct qusb2_phy_cfg *cfg;
>>  bool has_se_clk_scheme;
>> +bool phy_initialized;
>> +bool powered_on;
> Is the powered_on flag here because the controller driver has unbalanced
> power on calls to the phy? Same comment applies for the phy_initialized
> flag. Both of these look like workarounds for some odd behavior in the
> controller driver.
phy_initialized flag is to make runtime_suspend/resume no-ops
until PHY gets initialized.
powered_on flag is not related to any issue issue in core (as of now).
I just added that to bail out early from phy power_on/off which is now
called from phy_init/exit and runtime_suspend/resume as well.





Re: [PATCH v3 2/3] usb: phy: Add USB charger support

2017-07-25 Thread Manu Gautam
Hi,


On 7/25/2017 1:30 PM, Baolin Wang wrote:
> This patch introduces the usb charger support based on usb phy that
> makes an enhancement to a power driver. The basic conception of the
> usb charger is that, when one usb charger is added or removed by
> reporting from the extcon device state change, the usb charger will
> report to power user to set the current limitation.
>
> Power user can register a notifiee on the usb phy by issuing
> usb_register_notifier() to get notified by charger status changes
> or charger current changes.

Why can't we use power_supply framework for this?
Power user can register usb power_supply and USB PHY driver
can update charging current using - power_supply_set_property().



> we can notify what current to be drawn to power user according to
> different charger type, and now we have 2 methods to get charger type.
> One is get charger type from extcon subsystem, which also means the
> charger state changes. Another is we can get the charger type from
> USB controller detecting or PMIC detecting, and the charger state
> changes should be told by issuing usb_phy_set_charger_state().
>
> Signed-off-by: Baolin Wang 
> ---
>  drivers/usb/phy/phy.c   |  272 
> +++
>  include/linux/usb/phy.h |   49 +

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH v1 2/6] phy: qcom-qmp: Power-on PHY before initialization

2017-08-09 Thread Manu Gautam


On 7/21/2017 4:31 PM, Manu Gautam wrote:
>  }
> @@ -729,19 +771,17 @@ static int qcom_qmp_phy_init(struct phy *phy)
>   void __iomem *pcs = qphy->pcs;
>   void __iomem *status;
>   unsigned int mask, val;
> - int ret, i;
> + int ret;
>  
>   dev_vdbg(qmp->dev, "Initializing QMP phy\n");
>  
> - for (i = 0; i < qmp->cfg->num_clks; i++) {
> - ret = clk_prepare_enable(qmp->clks[i]);
> - if (ret) {
> - dev_err(qmp->dev, "failed to enable %s clk, err=%d\n",
> - qmp->cfg->clk_list[i], ret);
> - while (--i >= 0)
> - clk_disable_unprepare(qmp->clks[i]);
> - }
> - }
> + ret = qcom_qmp_phy_poweron(qmp);
> + if (ret)
> + return ret;
> +
> + ret = qcom_qmp_phy_enable_clocks(qmp);
> + if (ret)
> + goto err_clk_enable;
>  
>   ret = qcom_qmp_phy_com_init(qmp);

In next version I will move poweron and clock_enable to com_init
as PCI QMP PHY might use multiple PHY instances (for each lane) each of
them will call phy_init/exit.
qcom_qmp_phy_com_init executed only once, hence better
suited for turning ON clocks/regulators.

>   if (ret)
> @@ -801,8 +841,9 @@ static int qcom_qmp_phy_init(struct phy *phy)
>  err_lane_rst:
>   qcom_qmp_phy_com_exit(qmp);
>  err_com_init:
> - while (--i >= 0)
> - clk_disable_unprepare(qmp->clks[i]);
> + qcom_qmp_phy_disable_clocks(qmp);
> +err_clk_enable:
> + qcom_qmp_phy_poweroff(qmp);
>  
>   return ret;
>  }
> @@ -812,7 +853,6 @@ static int qcom_qmp_phy_exit(struct phy *phy)
>   struct qmp_phy *qphy = phy_get_drvdata(phy);
>   struct qcom_qmp *qmp = qphy->qmp;
>   const struct qmp_phy_cfg *cfg = qmp->cfg;
> - int i = cfg->num_clks;
>  
>   clk_disable_unprepare(qphy->pipe_clk);
>  
> @@ -830,8 +870,9 @@ static int qcom_qmp_phy_exit(struct phy *phy)
>  
>   qcom_qmp_phy_com_exit(qmp);
>  
> - while (--i >= 0)
> - clk_disable_unprepare(qmp->clks[i]);
> + qcom_qmp_phy_disable_clocks(qmp);
> +
> + qcom_qmp_phy_poweroff(qmp);

On similar lines will be moving these to qcom_qmp_phy_com_exit().
>  
>   return 0;
>  }
> @@ -958,8 +999,6 @@ static int phy_pipe_clk_register(struct qcom_qmp *qmp, 
> int id)
>  static const struct phy_ops qcom_qmp_phy_gen_ops = {
>   .init   = qcom_qmp_phy_init,
>   .exit   = qcom_qmp_phy_exit,
> - .power_on   = qcom_qmp_phy_poweron,
> - .power_off  = qcom_qmp_phy_poweroff,
>   .owner  = THIS_MODULE,
>  };
>  

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH v8] usb: dwc3: of-simple: Add support to get resets for the device

2017-10-20 Thread Manu Gautam
Hi,


On 10/19/2017 5:17 PM, Philipp Zabel wrote:
> From: Vivek Gautam 
>
> Add support to get a list of resets available for the device.
> These resets must be kept de-asserted until the device is
> in use.
>
> Signed-off-by: Vivek Gautam 
> [p.za...@pengutronix.de: switch to hidden reset control array]
> Signed-off-by: Philipp Zabel 
> ---
> v7: Rebased onto git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git 
> testing/next
> ---
>  drivers/usb/dwc3/dwc3-of-simple.c | 27 +--
>  1 file changed, 25 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/usb/dwc3/dwc3-of-simple.c 
> b/drivers/usb/dwc3/dwc3-of-simple.c
> index e129c32780818..ceea1619f8aa3 100644
> --- a/drivers/usb/dwc3/dwc3-of-simple.c
> +++ b/drivers/usb/dwc3/dwc3-of-simple.c
> @@ -28,11 +28,13 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  
>  struct dwc3_of_simple {
>   struct device   *dev;
>   struct clk  **clks;
>   int num_clocks;
> + struct reset_control*resets;
>  };
>  
>  static int dwc3_of_simple_clk_init(struct dwc3_of_simple *simple, int count)
> @@ -95,10 +97,21 @@ static int dwc3_of_simple_probe(struct platform_device 
> *pdev)
>   platform_set_drvdata(pdev, simple);
>   simple->dev = dev;
>  
> + simple->resets = of_reset_control_array_get_optional_exclusive(np);
> + if (IS_ERR(simple->resets)) {
> + ret = PTR_ERR(simple->resets);
> + dev_err(dev, "failed to get device resets, err=%d\n", ret);
> + return ret;
> + }
> +
> + ret = reset_control_deassert(simple->resets);
> + if (ret)
> + goto err_resetc_put;
> +

Are these reset signals asserted by default after power on?
I think correct way to handle this should be to have explicit 
reset_control_assert
before deassert.

>   ret = dwc3_of_simple_clk_init(simple, of_count_phandle_with_args(np,
>   "clocks", "#clock-cells"));
>   if (ret)
> - return ret;
> + goto err_resetc_assert;

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [RESEND PATCH 1/3] usb: dwc3: Don't reinitialize core during host bus-suspend/resume

2017-10-21 Thread Manu Gautam
Hi Felipe,

Let me know if patches in this series look fine to you.


On 9/27/2017 4:49 PM, Manu Gautam wrote:
> Driver powers-off PHYs and reinitializes DWC3 core and gadget on
> resume. While this works fine for gadget mode but in host
> mode there is not re-initialization of host stack. Also, resetting
> bus as part of bus_suspend/resume is not correct which could affect
> (or disconnect) connected devices.
> Fix this by not reinitializing core on suspend/resume in host mode
> for HOST only and OTG/drd configurations.
>
> Signed-off-by: Manu Gautam 
> ---
>  drivers/usb/dwc3/core.c | 43 ---
>  1 file changed, 20 insertions(+), 23 deletions(-)
>
> diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
> index 03474d3..f75613f 100644
> --- a/drivers/usb/dwc3/core.c
> +++ b/drivers/usb/dwc3/core.c
> @@ -927,6 +927,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
>  
>   switch (dwc->dr_mode) {
>   case USB_DR_MODE_PERIPHERAL:
> + dwc->current_dr_role = DWC3_GCTL_PRTCAP_DEVICE;
>   dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
>  
>   if (dwc->usb2_phy)
> @@ -942,6 +943,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
>   }
>   break;
>   case USB_DR_MODE_HOST:
> + dwc->current_dr_role = DWC3_GCTL_PRTCAP_HOST;
>   dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
>  
>   if (dwc->usb2_phy)
> @@ -1293,21 +1295,19 @@ static int dwc3_suspend_common(struct dwc3 *dwc)
>  {
>   unsigned long   flags;
>  
> - switch (dwc->dr_mode) {
> - case USB_DR_MODE_PERIPHERAL:
> - case USB_DR_MODE_OTG:
> + switch (dwc->current_dr_role) {
> + case DWC3_GCTL_PRTCAP_DEVICE:
>   spin_lock_irqsave(&dwc->lock, flags);
>   dwc3_gadget_suspend(dwc);
>   spin_unlock_irqrestore(&dwc->lock, flags);
> + dwc3_core_exit(dwc);
>   break;
> - case USB_DR_MODE_HOST:
> + case DWC3_GCTL_PRTCAP_HOST:
>   default:
>   /* do nothing */
>   break;
>   }
>  
> - dwc3_core_exit(dwc);
> -
>   return 0;
>  }
>  
> @@ -1316,18 +1316,17 @@ static int dwc3_resume_common(struct dwc3 *dwc)
>   unsigned long   flags;
>   int ret;
>  
> - ret = dwc3_core_init(dwc);
> - if (ret)
> - return ret;
> + switch (dwc->current_dr_role) {
> + case DWC3_GCTL_PRTCAP_DEVICE:
> + ret = dwc3_core_init(dwc);
> + if (ret)
> + return ret;
>  
> - switch (dwc->dr_mode) {
> - case USB_DR_MODE_PERIPHERAL:
> - case USB_DR_MODE_OTG:
>   spin_lock_irqsave(&dwc->lock, flags);
>   dwc3_gadget_resume(dwc);
>   spin_unlock_irqrestore(&dwc->lock, flags);
> - /* FALLTHROUGH */
> - case USB_DR_MODE_HOST:
> + break;
> + case DWC3_GCTL_PRTCAP_HOST:
>   default:
>   /* do nothing */
>   break;
> @@ -1338,7 +1337,7 @@ static int dwc3_resume_common(struct dwc3 *dwc)
>  
>  static int dwc3_runtime_checks(struct dwc3 *dwc)
>  {
> - switch (dwc->dr_mode) {
> + switch (dwc->current_dr_role) {
>   case USB_DR_MODE_PERIPHERAL:
>   case USB_DR_MODE_OTG:
>   if (dwc->connected)
> @@ -1381,12 +1380,11 @@ static int dwc3_runtime_resume(struct device *dev)
>   if (ret)
>   return ret;
>  
> - switch (dwc->dr_mode) {
> - case USB_DR_MODE_PERIPHERAL:
> - case USB_DR_MODE_OTG:
> + switch (dwc->current_dr_role) {
> + case DWC3_GCTL_PRTCAP_DEVICE:
>   dwc3_gadget_process_pending_events(dwc);
>   break;
> - case USB_DR_MODE_HOST:
> + case DWC3_GCTL_PRTCAP_HOST:
>   default:
>   /* do nothing */
>   break;
> @@ -1402,13 +1400,12 @@ static int dwc3_runtime_idle(struct device *dev)
>  {
>   struct dwc3 *dwc = dev_get_drvdata(dev);
>  
> - switch (dwc->dr_mode) {
> - case USB_DR_MODE_PERIPHERAL:
> - case USB_DR_MODE_OTG:
> + switch (dwc->current_dr_role) {
> + case DWC3_GCTL_PRTCAP_DEVICE:
>   if (dwc3_runtime_checks(dwc))
>   return -EBUSY;
>   break;
> - case USB_DR_MODE_HOST:
> + case DWC3_GCTL_PRTCAP_HOST:
>   default:
>   /* do nothing */
>   break;

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH v2 14/17] phy: qcom-qusb2: Set vbus sw-override signal in device mode

2017-10-23 Thread Manu Gautam
Hi Kishon,

Please review this so that I can re-submit patch-set based on this approach.

On 10/9/2017 1:33 PM, Manu Gautam wrote:
> Hi Kishon
>
> On 10/5/2017 2:38 PM, Manu Gautam wrote:
>> Kishon,
>> What would you suggest here?
>> Should we add new calls e.g. phy_get/set_current_speed like::
>>
>> diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h
>> index 78bb0d7..41d9ec2 100644
>> --- a/include/linux/phy/phy.h
>> +++ b/include/linux/phy/phy.h
>> @@ -29,6 +29,14 @@ enum phy_mode {
>>     PHY_MODE_USB_OTG,
>>  };
>>
>> +enum phy_speed {
>> +   PHY_SPEED_INVALID,
>> +   PHY_SPEED_USB_LS,
>> +   PHY_SPEED_USB_FS_HS,
>> +   PHY_SPEED_USB_SS,
>> +};
>> +
>>  /**
>>   * struct phy_ops - set of function pointers for performing phy operations
>>   * @init: operation to be performed for initializing phy
>> @@ -45,6 +53,7 @@ struct phy_ops {
>>     int (*power_on)(struct phy *phy);
>>     int (*power_off)(struct phy *phy);
>>     int (*set_mode)(struct phy *phy, enum phy_mode mode);
>> +   int (*set_speed)(struct phy *phy, enum phy_speed speed);
>>     int (*reset)(struct phy *phy);
>>     struct module *owner;
>>  };
>>
> @Kishon,
> Let me know if we can add set_speed to phy_ops. We need this for glue
> driver to notify PHY of current connection speed to enable appropriate
> wakeup interrupts.
>
>

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v3 01/16] phy: qcom-qmp: Fix phy pipe clock gating

2017-11-21 Thread Manu Gautam
From: Vivek Gautam 

Pipe clock comes out of the phy and is available as long as
the phy is turned on. Clock controller fails to gate this
clock after the phy is turned off and generates a warning.

/ # [   33.048561] gcc_usb3_phy_pipe_clk status stuck at 'on'
[   33.048585] [ cut here ]
[   33.052621] WARNING: CPU: 1 PID: 18 at ../drivers/clk/qcom/clk-branch.c:97 
clk_branch_wait+0xf0/0x108
[   33.057384] Modules linked in:
[   33.066497] CPU: 1 PID: 18 Comm: kworker/1:0 Tainted: GW   
4.12.0-rc7-00024-gfe926e34c36d-dirty #96
[   33.069451] Hardware name: Qualcomm Technologies, Inc. DB820c (DT)
...
[   33.278565] [] clk_branch_wait+0xf0/0x108
[   33.286375] [] clk_branch2_disable+0x28/0x34
[   33.291761] [] clk_core_disable+0x5c/0x88
[   33.297660] [] clk_core_disable_lock+0x20/0x34
[   33.303129] [] clk_disable+0x1c/0x24
[   33.309384] [] qcom_qmp_phy_poweroff+0x20/0x48
[   33.314328] [] phy_power_off+0x80/0xdc
[   33.320492] [] dwc3_core_exit+0x94/0xa0
[   33.325784] [] dwc3_suspend_common+0x50/0x60
[   33.331080] [] dwc3_runtime_suspend+0x48/0x6c
[   33.336810] [] pm_generic_runtime_suspend+0x28/0x38
[   33.342627] [] __rpm_callback+0x150/0x254
[   33.349222] [] rpm_callback+0x24/0x78
[   33.354604] [] rpm_suspend+0xe0/0x4e4
[   33.359813] [] pm_runtime_work+0xdc/0xf0
[   33.365028] [] process_one_work+0x12c/0x28c
[   33.370576] [] worker_thread+0x58/0x3b8
[   33.376393] [] kthread+0x100/0x12c
[   33.381776] [] ret_from_fork+0x10/0x50

Fix this by enabling pipe clock at the end of phy_init(), and disabling
it as the first thing in phy_exit().

Fixes: e78f3d15e115 ("phy: qcom-qmp: new qmp phy driver for qcom-chipsets")
Signed-off-by: Vivek Gautam 
Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qmp.c | 26 --
 1 file changed, 12 insertions(+), 14 deletions(-)

diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c 
b/drivers/phy/qualcomm/phy-qcom-qmp.c
index e17f035..76acaec 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.c
@@ -731,19 +731,10 @@ static int qcom_qmp_phy_poweron(struct phy *phy)
 
/* turn on regulator supplies */
ret = regulator_bulk_enable(num, qmp->vregs);
-   if (ret) {
+   if (ret)
dev_err(qmp->dev, "failed to enable regulators, err=%d\n", ret);
-   return ret;
-   }
-
-   ret = clk_prepare_enable(qphy->pipe_clk);
-   if (ret) {
-   dev_err(qmp->dev, "pipe_clk enable failed, err=%d\n", ret);
-   regulator_bulk_disable(num, qmp->vregs);
-   return ret;
-   }
 
-   return 0;
+   return ret;
 }
 
 static int qcom_qmp_phy_poweroff(struct phy *phy)
@@ -751,8 +742,6 @@ static int qcom_qmp_phy_poweroff(struct phy *phy)
struct qmp_phy *qphy = phy_get_drvdata(phy);
struct qcom_qmp *qmp = qphy->qmp;
 
-   clk_disable_unprepare(qphy->pipe_clk);
-
regulator_bulk_disable(qmp->cfg->num_vregs, qmp->vregs);
 
return 0;
@@ -915,7 +904,14 @@ static int qcom_qmp_phy_init(struct phy *phy)
goto err_pcs_ready;
}
 
-   return ret;
+   /* phy is initialized; we can turn on the pipe clock now */
+   ret = clk_prepare_enable(qphy->pipe_clk);
+   if (ret) {
+   dev_err(qmp->dev, "pipe_clk enable failed, err=%d\n", ret);
+   goto err_pcs_ready;
+   }
+
+   return 0;
 
 err_pcs_ready:
if (cfg->has_lane_rst)
@@ -936,6 +932,8 @@ static int qcom_qmp_phy_exit(struct phy *phy)
const struct qmp_phy_cfg *cfg = qmp->cfg;
int i = cfg->num_clks;
 
+   clk_disable_unprepare(qphy->pipe_clk);
+
/* PHY reset */
qphy_setbits(qphy->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v3 02/16] phy: qcom-qmp: Adapt to clk_bulk_* APIs

2017-11-21 Thread Manu Gautam
From: Vivek Gautam 

Move from using array of clocks to clk_bulk_* APIs that
are available now.

Signed-off-by: Vivek Gautam 
Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qmp.c | 50 -
 1 file changed, 16 insertions(+), 34 deletions(-)

diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c 
b/drivers/phy/qualcomm/phy-qcom-qmp.c
index 76acaec..90794dd 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.c
@@ -555,7 +555,7 @@ struct qcom_qmp {
struct device *dev;
void __iomem *serdes;
 
-   struct clk **clks;
+   struct clk_bulk_data *clks;
struct reset_control **resets;
struct regulator_bulk_data *vregs;
 
@@ -848,22 +848,19 @@ static int qcom_qmp_phy_init(struct phy *phy)
void __iomem *pcs = qphy->pcs;
void __iomem *status;
unsigned int mask, val;
-   int ret, i;
+   int ret;
 
dev_vdbg(qmp->dev, "Initializing QMP phy\n");
 
-   for (i = 0; i < qmp->cfg->num_clks; i++) {
-   ret = clk_prepare_enable(qmp->clks[i]);
-   if (ret) {
-   dev_err(qmp->dev, "failed to enable %s clk, err=%d\n",
-   qmp->cfg->clk_list[i], ret);
-   goto err_clk;
-   }
+   ret = clk_bulk_prepare_enable(cfg->num_clks, qmp->clks);
+   if (ret) {
+   dev_err(qmp->dev, "failed to enable clks, err=%d\n", ret);
+   return ret;
}
 
ret = qcom_qmp_phy_com_init(qmp);
if (ret)
-   goto err_clk;
+   goto err_com_init;
 
if (cfg->has_lane_rst) {
ret = reset_control_deassert(qphy->lane_rst);
@@ -918,9 +915,8 @@ static int qcom_qmp_phy_init(struct phy *phy)
reset_control_assert(qphy->lane_rst);
 err_lane_rst:
qcom_qmp_phy_com_exit(qmp);
-err_clk:
-   while (--i >= 0)
-   clk_disable_unprepare(qmp->clks[i]);
+err_com_init:
+   clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks);
 
return ret;
 }
@@ -930,7 +926,6 @@ static int qcom_qmp_phy_exit(struct phy *phy)
struct qmp_phy *qphy = phy_get_drvdata(phy);
struct qcom_qmp *qmp = qphy->qmp;
const struct qmp_phy_cfg *cfg = qmp->cfg;
-   int i = cfg->num_clks;
 
clk_disable_unprepare(qphy->pipe_clk);
 
@@ -948,8 +943,7 @@ static int qcom_qmp_phy_exit(struct phy *phy)
 
qcom_qmp_phy_com_exit(qmp);
 
-   while (--i >= 0)
-   clk_disable_unprepare(qmp->clks[i]);
+   clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks);
 
return 0;
 }
@@ -998,29 +992,17 @@ static int qcom_qmp_phy_reset_init(struct device *dev)
 static int qcom_qmp_phy_clk_init(struct device *dev)
 {
struct qcom_qmp *qmp = dev_get_drvdata(dev);
-   int ret, i;
+   int num = qmp->cfg->num_clks;
+   int i;
 
-   qmp->clks = devm_kcalloc(dev, qmp->cfg->num_clks,
-sizeof(*qmp->clks), GFP_KERNEL);
+   qmp->clks = devm_kcalloc(dev, num, sizeof(*qmp->clks), GFP_KERNEL);
if (!qmp->clks)
return -ENOMEM;
 
-   for (i = 0; i < qmp->cfg->num_clks; i++) {
-   struct clk *_clk;
-   const char *name = qmp->cfg->clk_list[i];
-
-   _clk = devm_clk_get(dev, name);
-   if (IS_ERR(_clk)) {
-   ret = PTR_ERR(_clk);
-   if (ret != -EPROBE_DEFER)
-   dev_err(dev, "failed to get %s clk, %d\n",
-   name, ret);
-   return ret;
-   }
-   qmp->clks[i] = _clk;
-   }
+   for (i = 0; i < num; i++)
+   qmp->clks->id = qmp->cfg->clk_list[i];
 
-   return 0;
+   return devm_clk_bulk_get(dev, num, qmp->clks);
 }
 
 /*
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v3 03/16] phy: qcom-qmp: Power-on PHY before initialization

2017-11-21 Thread Manu Gautam
PHY must be powered on before turning ON clocks and
attempting to initialize it. Driver is exposing
separate init and power_on routines for this.
Apparently USB dwc3 core driver performs power-on after
init. Also, poweron and init for QMP PHY need to be
executed together always, hence remove poweron callback
from phy_ops and explicitly perform this from com_init,
similar changes needed for poweroff. On similar lines move
clk_enable from init to com_init which can be called once
for multi lane PHYs.

Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qmp.c | 61 +
 1 file changed, 21 insertions(+), 40 deletions(-)

diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c 
b/drivers/phy/qualcomm/phy-qcom-qmp.c
index 90794dd..2f427e3 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.c
@@ -720,33 +720,6 @@ static void qcom_qmp_phy_configure(void __iomem *base,
}
 }
 
-static int qcom_qmp_phy_poweron(struct phy *phy)
-{
-   struct qmp_phy *qphy = phy_get_drvdata(phy);
-   struct qcom_qmp *qmp = qphy->qmp;
-   int num = qmp->cfg->num_vregs;
-   int ret;
-
-   dev_vdbg(&phy->dev, "Powering on QMP phy\n");
-
-   /* turn on regulator supplies */
-   ret = regulator_bulk_enable(num, qmp->vregs);
-   if (ret)
-   dev_err(qmp->dev, "failed to enable regulators, err=%d\n", ret);
-
-   return ret;
-}
-
-static int qcom_qmp_phy_poweroff(struct phy *phy)
-{
-   struct qmp_phy *qphy = phy_get_drvdata(phy);
-   struct qcom_qmp *qmp = qphy->qmp;
-
-   regulator_bulk_disable(qmp->cfg->num_vregs, qmp->vregs);
-
-   return 0;
-}
-
 static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
 {
const struct qmp_phy_cfg *cfg = qmp->cfg;
@@ -759,6 +732,19 @@ static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
return 0;
}
 
+   /* turn on regulator supplies */
+   ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs);
+   if (ret) {
+   mutex_unlock(&qmp->phy_mutex);
+   return ret;
+   }
+
+   ret = clk_bulk_prepare_enable(cfg->num_clks, qmp->clks);
+   if (ret) {
+   dev_err(qmp->dev, "failed to enable clks, err=%d\n", ret);
+   goto err_clk_enable;
+   }
+
for (i = 0; i < cfg->num_resets; i++) {
ret = reset_control_deassert(qmp->resets[i]);
if (ret) {
@@ -803,6 +789,9 @@ static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
 err_rst:
while (--i >= 0)
reset_control_assert(qmp->resets[i]);
+   clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks);
+err_clk_enable:
+   regulator_bulk_disable(cfg->num_vregs, qmp->vregs);
mutex_unlock(&qmp->phy_mutex);
 
return ret;
@@ -832,6 +821,10 @@ static int qcom_qmp_phy_com_exit(struct qcom_qmp *qmp)
while (--i >= 0)
reset_control_assert(qmp->resets[i]);
 
+   clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks);
+
+   regulator_bulk_disable(cfg->num_vregs, qmp->vregs);
+
mutex_unlock(&qmp->phy_mutex);
 
return 0;
@@ -852,15 +845,9 @@ static int qcom_qmp_phy_init(struct phy *phy)
 
dev_vdbg(qmp->dev, "Initializing QMP phy\n");
 
-   ret = clk_bulk_prepare_enable(cfg->num_clks, qmp->clks);
-   if (ret) {
-   dev_err(qmp->dev, "failed to enable clks, err=%d\n", ret);
-   return ret;
-   }
-
ret = qcom_qmp_phy_com_init(qmp);
if (ret)
-   goto err_com_init;
+   return ret;
 
if (cfg->has_lane_rst) {
ret = reset_control_deassert(qphy->lane_rst);
@@ -915,8 +902,6 @@ static int qcom_qmp_phy_init(struct phy *phy)
reset_control_assert(qphy->lane_rst);
 err_lane_rst:
qcom_qmp_phy_com_exit(qmp);
-err_com_init:
-   clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks);
 
return ret;
 }
@@ -943,8 +928,6 @@ static int qcom_qmp_phy_exit(struct phy *phy)
 
qcom_qmp_phy_com_exit(qmp);
 
-   clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks);
-
return 0;
 }
 
@@ -1057,8 +1040,6 @@ static int phy_pipe_clk_register(struct qcom_qmp *qmp, 
struct device_node *np)
 static const struct phy_ops qcom_qmp_phy_gen_ops = {
.init   = qcom_qmp_phy_init,
.exit   = qcom_qmp_phy_exit,
-   .power_on   = qcom_qmp_phy_poweron,
-   .power_off  = qcom_qmp_phy_poweroff,
.owner  = THIS_MODULE,
 };
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v3 04/16] phy: qcom-qusb2: Power-on PHY before initialization

2017-11-21 Thread Manu Gautam
PHY must be powered on before turning ON clocks and
attempting to initialize it. Driver is exposing
separate init and power_on routines for this.
Apparently USB dwc3 core driver performs power-on
after init. Also, poweron and init for QUSB2 PHY
need to be executed together always, hence remove
poweron callback from phy_ops and explicitly perform
this from init, similar changes needed for poweroff.

Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qusb2.c | 47 +++
 1 file changed, 15 insertions(+), 32 deletions(-)

diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c 
b/drivers/phy/qualcomm/phy-qcom-qusb2.c
index 6c57524..4a5b2a1 100644
--- a/drivers/phy/qualcomm/phy-qcom-qusb2.c
+++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c
@@ -195,54 +195,31 @@ static void qusb2_phy_set_tune2_param(struct qusb2_phy 
*qphy)
qusb2_setbits(qphy->base, QUSB2PHY_PORT_TUNE2, val[0] << 0x4);
 }
 
-static int qusb2_phy_poweron(struct phy *phy)
+static int qusb2_phy_init(struct phy *phy)
 {
struct qusb2_phy *qphy = phy_get_drvdata(phy);
-   int num = ARRAY_SIZE(qphy->vregs);
+   unsigned int val;
+   unsigned int clk_scheme;
int ret;
 
-   dev_vdbg(&phy->dev, "%s(): Powering-on QUSB2 phy\n", __func__);
+   dev_vdbg(&phy->dev, "%s(): Initializing QUSB2 phy\n", __func__);
 
/* turn on regulator supplies */
-   ret = regulator_bulk_enable(num, qphy->vregs);
+   ret = regulator_bulk_enable(ARRAY_SIZE(qphy->vregs), qphy->vregs);
if (ret)
return ret;
 
ret = clk_prepare_enable(qphy->iface_clk);
if (ret) {
dev_err(&phy->dev, "failed to enable iface_clk, %d\n", ret);
-   regulator_bulk_disable(num, qphy->vregs);
-   return ret;
+   goto poweroff_phy;
}
 
-   return 0;
-}
-
-static int qusb2_phy_poweroff(struct phy *phy)
-{
-   struct qusb2_phy *qphy = phy_get_drvdata(phy);
-
-   clk_disable_unprepare(qphy->iface_clk);
-
-   regulator_bulk_disable(ARRAY_SIZE(qphy->vregs), qphy->vregs);
-
-   return 0;
-}
-
-static int qusb2_phy_init(struct phy *phy)
-{
-   struct qusb2_phy *qphy = phy_get_drvdata(phy);
-   unsigned int val;
-   unsigned int clk_scheme;
-   int ret;
-
-   dev_vdbg(&phy->dev, "%s(): Initializing QUSB2 phy\n", __func__);
-
/* enable ahb interface clock to program phy */
ret = clk_prepare_enable(qphy->cfg_ahb_clk);
if (ret) {
dev_err(&phy->dev, "failed to enable cfg ahb clock, %d\n", ret);
-   return ret;
+   goto disable_iface_clk;
}
 
/* Perform phy reset */
@@ -344,6 +321,11 @@ static int qusb2_phy_init(struct phy *phy)
reset_control_assert(qphy->phy_reset);
 disable_ahb_clk:
clk_disable_unprepare(qphy->cfg_ahb_clk);
+disable_iface_clk:
+   clk_disable_unprepare(qphy->iface_clk);
+poweroff_phy:
+   regulator_bulk_disable(ARRAY_SIZE(qphy->vregs), qphy->vregs);
+
return ret;
 }
 
@@ -361,6 +343,9 @@ static int qusb2_phy_exit(struct phy *phy)
reset_control_assert(qphy->phy_reset);
 
clk_disable_unprepare(qphy->cfg_ahb_clk);
+   clk_disable_unprepare(qphy->iface_clk);
+
+   regulator_bulk_disable(ARRAY_SIZE(qphy->vregs), qphy->vregs);
 
return 0;
 }
@@ -368,8 +353,6 @@ static int qusb2_phy_exit(struct phy *phy)
 static const struct phy_ops qusb2_phy_gen_ops = {
.init   = qusb2_phy_init,
.exit   = qusb2_phy_exit,
-   .power_on   = qusb2_phy_poweron,
-   .power_off  = qusb2_phy_poweroff,
.owner  = THIS_MODULE,
 };
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v3 10/16] phy: qcom-qmp: Move register offsets to header file

2017-11-21 Thread Manu Gautam
New revision (v3) of QMP PHY uses different offsets
for almost all of the registers. Hence, move these
definitions to header file so that updated offsets
can be added for QMP v3.

Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qmp.c | 119 +--
 drivers/phy/qualcomm/phy-qcom-qmp.h | 137 
 2 files changed, 138 insertions(+), 118 deletions(-)
 create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp.h

diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c 
b/drivers/phy/qualcomm/phy-qcom-qmp.c
index 263cf50..15a734f 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.c
@@ -31,124 +31,7 @@
 
 #include 
 
-/* QMP PHY QSERDES COM registers */
-#define QSERDES_COM_BG_TIMER   0x00c
-#define QSERDES_COM_SSC_EN_CENTER  0x010
-#define QSERDES_COM_SSC_ADJ_PER1   0x014
-#define QSERDES_COM_SSC_ADJ_PER2   0x018
-#define QSERDES_COM_SSC_PER1   0x01c
-#define QSERDES_COM_SSC_PER2   0x020
-#define QSERDES_COM_SSC_STEP_SIZE1 0x024
-#define QSERDES_COM_SSC_STEP_SIZE2 0x028
-#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN0x034
-#define QSERDES_COM_CLK_ENABLE10x038
-#define QSERDES_COM_SYS_CLK_CTRL   0x03c
-#define QSERDES_COM_SYSCLK_BUF_ENABLE  0x040
-#define QSERDES_COM_PLL_IVCO   0x048
-#define QSERDES_COM_LOCK_CMP1_MODE00x04c
-#define QSERDES_COM_LOCK_CMP2_MODE00x050
-#define QSERDES_COM_LOCK_CMP3_MODE00x054
-#define QSERDES_COM_LOCK_CMP1_MODE10x058
-#define QSERDES_COM_LOCK_CMP2_MODE10x05c
-#define QSERDES_COM_LOCK_CMP3_MODE10x060
-#define QSERDES_COM_BG_TRIM0x070
-#define QSERDES_COM_CLK_EP_DIV 0x074
-#define QSERDES_COM_CP_CTRL_MODE0  0x078
-#define QSERDES_COM_CP_CTRL_MODE1  0x07c
-#define QSERDES_COM_PLL_RCTRL_MODE00x084
-#define QSERDES_COM_PLL_RCTRL_MODE10x088
-#define QSERDES_COM_PLL_CCTRL_MODE00x090
-#define QSERDES_COM_PLL_CCTRL_MODE10x094
-#define QSERDES_COM_BIAS_EN_CTRL_BY_PSM0x0a8
-#define QSERDES_COM_SYSCLK_EN_SEL  0x0ac
-#define QSERDES_COM_RESETSM_CNTRL  0x0b4
-#define QSERDES_COM_RESTRIM_CTRL   0x0bc
-#define QSERDES_COM_RESCODE_DIV_NUM0x0c4
-#define QSERDES_COM_LOCK_CMP_EN0x0c8
-#define QSERDES_COM_LOCK_CMP_CFG   0x0cc
-#define QSERDES_COM_DEC_START_MODE00x0d0
-#define QSERDES_COM_DEC_START_MODE10x0d4
-#define QSERDES_COM_DIV_FRAC_START1_MODE0  0x0dc
-#define QSERDES_COM_DIV_FRAC_START2_MODE0  0x0e0
-#define QSERDES_COM_DIV_FRAC_START3_MODE0  0x0e4
-#define QSERDES_COM_DIV_FRAC_START1_MODE1  0x0e8
-#define QSERDES_COM_DIV_FRAC_START2_MODE1  0x0ec
-#define QSERDES_COM_DIV_FRAC_START3_MODE1  0x0f0
-#define QSERDES_COM_INTEGLOOP_GAIN0_MODE0  0x108
-#define QSERDES_COM_INTEGLOOP_GAIN1_MODE0  0x10c
-#define QSERDES_COM_INTEGLOOP_GAIN0_MODE1  0x110
-#define QSERDES_COM_INTEGLOOP_GAIN1_MODE1  0x114
-#define QSERDES_COM_VCO_TUNE_CTRL  0x124
-#define QSERDES_COM_VCO_TUNE_MAP   0x128
-#define QSERDES_COM_VCO_TUNE1_MODE00x12c
-#define QSERDES_COM_VCO_TUNE2_MODE00x130
-#define QSERDES_COM_VCO_TUNE1_MODE10x134
-#define QSERDES_COM_VCO_TUNE2_MODE10x138
-#define QSERDES_COM_VCO_TUNE_TIMER10x144
-#define QSERDES_COM_VCO_TUNE_TIMER20x148
-#define QSERDES_COM_BG_CTRL0x170
-#define QSERDES_COM_CLK_SELECT 0x174
-#define QSERDES_COM_HSCLK_SEL  0x178
-#define QSERDES_COM_CORECLK_DIV0x184
-#define QSERDES_COM_CORE_CLK_EN0x18c
-#define QSERDES_COM_C_READY_STATUS 0x190
-#define QSERDES_COM_CMN_CONFIG 0x194
-#define QSERDES_COM_SVS_MODE_CLK_SEL   0x19c
-#define QSERDES_COM_DEBUG_BUS0 0x1a0
-#define QSERDES_COM_DEBUG_BUS1 0x1a4
-#define QSERDES_COM_DEBUG_BUS2 0x1a8
-#define QSERDES_COM_DEBUG_BUS3 0x1ac
-#define QSERDES_COM_DEBUG_BUS_SEL  0x1b0
-#define QSERDES_COM_CORECLK_DIV_MODE1

[PATCH v3 05/16] phy: qcom-qmp: Fix PHY block reset sequence

2017-11-21 Thread Manu Gautam
PHY block or asynchronous reset requires signal
to be asserted before de-asserting. Driver is only
de-asserting signal which is already low, hence
reset operation is a no-op. Fix this by asserting
signal first. Also, resetting requires PHY clocks
to be turned ON only after reset is finished. Fix
that as well.

Signed-off-by: Manu Gautam 
---
 drivers/phy/qualcomm/phy-qcom-qmp.c | 28 +++-
 1 file changed, 19 insertions(+), 9 deletions(-)

diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c 
b/drivers/phy/qualcomm/phy-qcom-qmp.c
index 2f427e3..aa27757 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.c
@@ -739,13 +739,16 @@ static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
return ret;
}
 
-   ret = clk_bulk_prepare_enable(cfg->num_clks, qmp->clks);
-   if (ret) {
-   dev_err(qmp->dev, "failed to enable clks, err=%d\n", ret);
-   goto err_clk_enable;
+   for (i = 0; i < cfg->num_resets; i++) {
+   ret = reset_control_assert(qmp->resets[i]);
+   if (ret) {
+   dev_err(qmp->dev, "%s reset assert failed\n",
+   cfg->reset_list[i]);
+   goto err_rst_assert;
+   }
}
 
-   for (i = 0; i < cfg->num_resets; i++) {
+   for (i = cfg->num_resets - 1; i >= 0; i--) {
ret = reset_control_deassert(qmp->resets[i]);
if (ret) {
dev_err(qmp->dev, "%s reset deassert failed\n",
@@ -754,6 +757,12 @@ static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
}
}
 
+   ret = clk_bulk_prepare_enable(cfg->num_clks, qmp->clks);
+   if (ret) {
+   dev_err(qmp->dev, "failed to enable clks, err=%d\n", ret);
+   goto err_rst;
+   }
+
if (cfg->has_phy_com_ctrl)
qphy_setbits(serdes, cfg->regs[QPHY_COM_POWER_DOWN_CONTROL],
 SW_PWRDN);
@@ -778,7 +787,7 @@ static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
if (ret) {
dev_err(qmp->dev,
"phy common block init timed-out\n");
-   goto err_rst;
+   goto err_com_init;
}
}
 
@@ -786,11 +795,12 @@ static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
 
return 0;
 
+err_com_init:
+   clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks);
 err_rst:
-   while (--i >= 0)
+   while (++i < cfg->num_resets)
reset_control_assert(qmp->resets[i]);
-   clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks);
-err_clk_enable:
+err_rst_assert:
regulator_bulk_disable(cfg->num_vregs, qmp->vregs);
mutex_unlock(&qmp->phy_mutex);
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



<    1   2   3   >