diff mbox series

[v2,4/6] usb: dwc3: reference clock period configuration

Message ID 0e99e3d453547ad2a8f4541090a03f3c80b80332.1628085910.git.baruch@tkos.co.il (mailing list archive)
State Not Applicable
Headers show
Series [v2,1/6] dt-bindings: phy: qcom,qmp: Add IPQ6018 USB3 PHY | expand

Commit Message

Baruch Siach Aug. 4, 2021, 2:05 p.m. UTC
From: Balaji Prakash J <bjagadee@codeaurora.org>

Set reference clock period when it differs from dwc3 default hardware
set.

Tested (USB2 only) on IPQ6010 SoC based board with 24 MHz reference
clock while hardware default is 19.2 MHz.

Signed-off-by: Balaji Prakash J <bjagadee@codeaurora.org>
[ baruch: rewrite commit message; drop GFLADJ code; remove 'quirk-' from
  property name; mention tested hardware ]
Signed-off-by: Baruch Siach <baruch@tkos.co.il>
---
v2:

  Remove snps,quirk-ref-clock-adjustment; not needed for tested hardware

  Rename DT property to snps,ref-clock-period (Thinh Nguyen)

  Use FIELD_PREP() (Bjorn Andersson)
---
 drivers/usb/dwc3/core.c | 29 +++++++++++++++++++++++++++++
 drivers/usb/dwc3/core.h |  6 ++++++
 2 files changed, 35 insertions(+)

Comments

Felipe Balbi Aug. 4, 2021, 2:11 p.m. UTC | #1
Hi,

Baruch Siach <baruch@tkos.co.il> writes:
> @@ -1371,6 +1398,8 @@ static void dwc3_get_properties(struct dwc3 *dwc)
>  				    &dwc->hsphy_interface);
>  	device_property_read_u32(dev, "snps,quirk-frame-length-adjustment",
>  				 &dwc->fladj);
> +	device_property_read_u32(dev, "snps,ref-clock-period",
> +				 &dwc->ref_clk_per);

I wonder if it would make more sense to pass an actual clock reference
here. If valid, then reconfigure the period to the value returned by
clk_get_rate(). It would avoid yet another DT binding. If we make the
clock optional, then we won't affect any other platforms. The clock
itself could be a regular fixed clock node.
Baruch Siach Aug. 4, 2021, 2:22 p.m. UTC | #2
Hi Felipe,

On Wed, Aug 04 2021, Felipe Balbi wrote:
> Baruch Siach <baruch@tkos.co.il> writes:
>> @@ -1371,6 +1398,8 @@ static void dwc3_get_properties(struct dwc3 *dwc)
>>  				    &dwc->hsphy_interface);
>>  	device_property_read_u32(dev, "snps,quirk-frame-length-adjustment",
>>  				 &dwc->fladj);
>> +	device_property_read_u32(dev, "snps,ref-clock-period",
>> +				 &dwc->ref_clk_per);
>
> I wonder if it would make more sense to pass an actual clock reference
> here. If valid, then reconfigure the period to the value returned by
> clk_get_rate(). It would avoid yet another DT binding. If we make the
> clock optional, then we won't affect any other platforms. The clock
> itself could be a regular fixed clock node.

Thinh Nguyen asked to add a dedicated DT property. He explained that
clk_get_rate() does not work for PCI hosted dwc3. This is the most
complete summary of the discussion:

  https://lore.kernel.org/r/c797e9cb-cae6-c0b6-5714-169c2ad79d32@synopsys.com

baruch
Felipe Balbi Aug. 4, 2021, 2:30 p.m. UTC | #3
Hi,

Baruch Siach <baruch@tkos.co.il> writes:
> Hi Felipe,
>
> On Wed, Aug 04 2021, Felipe Balbi wrote:
>> Baruch Siach <baruch@tkos.co.il> writes:
>>> @@ -1371,6 +1398,8 @@ static void dwc3_get_properties(struct dwc3 *dwc)
>>>  				    &dwc->hsphy_interface);
>>>  	device_property_read_u32(dev, "snps,quirk-frame-length-adjustment",
>>>  				 &dwc->fladj);
>>> +	device_property_read_u32(dev, "snps,ref-clock-period",
>>> +				 &dwc->ref_clk_per);
>>
>> I wonder if it would make more sense to pass an actual clock reference
>> here. If valid, then reconfigure the period to the value returned by
>> clk_get_rate(). It would avoid yet another DT binding. If we make the
>> clock optional, then we won't affect any other platforms. The clock
>> itself could be a regular fixed clock node.
>
> Thinh Nguyen asked to add a dedicated DT property. He explained that
> clk_get_rate() does not work for PCI hosted dwc3. This is the most
> complete summary of the discussion:

Hence the "optional" :-)

Or, perhaps, Thinh wants to use this for internal FPGA-based validation?

In that case, I'm okay with the property.
Thinh Nguyen Aug. 9, 2021, 10:13 p.m. UTC | #4
Felipe Balbi wrote:
> 
> Hi,
> 
> Baruch Siach <baruch@tkos.co.il> writes:
>> Hi Felipe,
>>
>> On Wed, Aug 04 2021, Felipe Balbi wrote:
>>> Baruch Siach <baruch@tkos.co.il> writes:
>>>> @@ -1371,6 +1398,8 @@ static void dwc3_get_properties(struct dwc3 *dwc)
>>>>  				    &dwc->hsphy_interface);
>>>>  	device_property_read_u32(dev, "snps,quirk-frame-length-adjustment",
>>>>  				 &dwc->fladj);
>>>> +	device_property_read_u32(dev, "snps,ref-clock-period",
>>>> +				 &dwc->ref_clk_per);
>>>
>>> I wonder if it would make more sense to pass an actual clock reference
>>> here. If valid, then reconfigure the period to the value returned by
>>> clk_get_rate(). It would avoid yet another DT binding. If we make the
>>> clock optional, then we won't affect any other platforms. The clock
>>> itself could be a regular fixed clock node.
>>
>> Thinh Nguyen asked to add a dedicated DT property. He explained that
>> clk_get_rate() does not work for PCI hosted dwc3. This is the most
>> complete summary of the discussion:
> 
> Hence the "optional" :-)
> 
> Or, perhaps, Thinh wants to use this for internal FPGA-based validation?
> 
> In that case, I'm okay with the property.
> 

We do use it for internal FPGA validation, but it should help for other
dwc3 PCI devices also.

BR,
Thinh
Rob Herring (Arm) Aug. 13, 2021, 5:27 p.m. UTC | #5
On Wed, Aug 04, 2021 at 05:22:27PM +0300, Baruch Siach wrote:
> Hi Felipe,
> 
> On Wed, Aug 04 2021, Felipe Balbi wrote:
> > Baruch Siach <baruch@tkos.co.il> writes:
> >> @@ -1371,6 +1398,8 @@ static void dwc3_get_properties(struct dwc3 *dwc)
> >>  				    &dwc->hsphy_interface);
> >>  	device_property_read_u32(dev, "snps,quirk-frame-length-adjustment",
> >>  				 &dwc->fladj);
> >> +	device_property_read_u32(dev, "snps,ref-clock-period",
> >> +				 &dwc->ref_clk_per);
> >
> > I wonder if it would make more sense to pass an actual clock reference
> > here. If valid, then reconfigure the period to the value returned by
> > clk_get_rate(). It would avoid yet another DT binding. If we make the
> > clock optional, then we won't affect any other platforms. The clock
> > itself could be a regular fixed clock node.
> 
> Thinh Nguyen asked to add a dedicated DT property. He explained that
> clk_get_rate() does not work for PCI hosted dwc3. This is the most
> complete summary of the discussion:
> 
>   https://lore.kernel.org/r/c797e9cb-cae6-c0b6-5714-169c2ad79d32@synopsys.com

PCI devices can have DT nodes with clock properties too. Or use the 
VID/PID to infer the frequency. Or use 'clock-frequency' property.

It boils down to we have lots of standard properties for clocks and 
clock configuration, so custom properties are a NAK.

Rob
Thinh Nguyen Aug. 13, 2021, 7:52 p.m. UTC | #6
Rob Herring wrote:
> On Wed, Aug 04, 2021 at 05:22:27PM +0300, Baruch Siach wrote:
>> Hi Felipe,
>>
>> On Wed, Aug 04 2021, Felipe Balbi wrote:
>>> Baruch Siach <baruch@tkos.co.il> writes:
>>>> @@ -1371,6 +1398,8 @@ static void dwc3_get_properties(struct dwc3 *dwc)
>>>>  				    &dwc->hsphy_interface);
>>>>  	device_property_read_u32(dev, "snps,quirk-frame-length-adjustment",
>>>>  				 &dwc->fladj);
>>>> +	device_property_read_u32(dev, "snps,ref-clock-period",
>>>> +				 &dwc->ref_clk_per);
>>>
>>> I wonder if it would make more sense to pass an actual clock reference
>>> here. If valid, then reconfigure the period to the value returned by
>>> clk_get_rate(). It would avoid yet another DT binding. If we make the
>>> clock optional, then we won't affect any other platforms. The clock
>>> itself could be a regular fixed clock node.
>>
>> Thinh Nguyen asked to add a dedicated DT property. He explained that
>> clk_get_rate() does not work for PCI hosted dwc3. This is the most
>> complete summary of the discussion:
>>
>>   https://urldefense.com/v3/__https://lore.kernel.org/r/c797e9cb-cae6-c0b6-5714-169c2ad79d32@synopsys.com__;!!A4F2R9G_pg!Nh6rqp_aOd8XIvqELvDRQe5ooZf13UZKwmn9lWcRgdbyMKpTMzL8HasrB1X2Ojvumo8g$ 
> 
> PCI devices can have DT nodes with clock properties too. Or use the 
> VID/PID to infer the frequency. Or use 'clock-frequency' property.
> 
> It boils down to we have lots of standard properties for clocks and 
> clock configuration, so custom properties are a NAK.
> 

Do we have DT node for the PCI device before discovering the device from
PCI bus enumeration? I don't think we can find the clock properties from
its configuration space. For our HAPS devices, we can't use VID/PID to
infer the frequency since our phy and ref clock may change.

Does "clock-frequency" mean ref clock? If so, let's use that?

Thanks,
Thinh
diff mbox series

Patch

diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index ba74ad7f6995..7ec5bfb5fc11 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -26,6 +26,7 @@ 
 #include <linux/acpi.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/reset.h>
+#include <linux/bitfield.h>
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
@@ -351,6 +352,29 @@  static void dwc3_frame_length_adjustment(struct dwc3 *dwc)
 	}
 }
 
+/**
+ * dwc3_ref_clk_period - Reference clock period configuration
+ *		Default reference clock period depends on hardware
+ *		configuration. For systems with reference clock that differs
+ *		from the default, this will set clock period in DWC3_GUCTL
+ *		register.
+ * @dwc: Pointer to our controller context structure
+ * @ref_clk_per: reference clock period in ns
+ */
+static void dwc3_ref_clk_period(struct dwc3 *dwc)
+{
+	u32 reg;
+
+	if (dwc->ref_clk_per == 0)
+		return;
+
+	reg = dwc3_readl(dwc->regs, DWC3_GUCTL);
+	reg &= ~DWC3_GUCTL_REFCLKPER_MASK;
+	reg |=  FIELD_PREP(DWC3_GUCTL_REFCLKPER_MASK, dwc->ref_clk_per);
+	dwc3_writel(dwc->regs, DWC3_GUCTL, reg);
+}
+
+
 /**
  * dwc3_free_one_event_buffer - Frees one event buffer
  * @dwc: Pointer to our controller context structure
@@ -1011,6 +1035,9 @@  static int dwc3_core_init(struct dwc3 *dwc)
 	/* Adjust Frame Length */
 	dwc3_frame_length_adjustment(dwc);
 
+	/* Adjust Reference Clock Period */
+	dwc3_ref_clk_period(dwc);
+
 	dwc3_set_incr_burst_type(dwc);
 
 	usb_phy_set_suspend(dwc->usb2_phy, 0);
@@ -1371,6 +1398,8 @@  static void dwc3_get_properties(struct dwc3 *dwc)
 				    &dwc->hsphy_interface);
 	device_property_read_u32(dev, "snps,quirk-frame-length-adjustment",
 				 &dwc->fladj);
+	device_property_read_u32(dev, "snps,ref-clock-period",
+				 &dwc->ref_clk_per);
 
 	dwc->dis_metastability_quirk = device_property_read_bool(dev,
 				"snps,dis_metastability_quirk");
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 5991766239ba..1e4e21ea9d97 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -386,6 +386,10 @@ 
 #define DWC3_GFLADJ_30MHZ_SDBND_SEL		BIT(7)
 #define DWC3_GFLADJ_30MHZ_MASK			0x3f
 
+/* Global User Control Register*/
+#define DWC3_GUCTL_REFCLKPER_MASK		0xffc00000
+#define DWC3_GUCTL_REFCLKPER_SEL		22
+
 /* Global User Control Register 2 */
 #define DWC3_GUCTL2_RST_ACTBITLATER		BIT(14)
 
@@ -969,6 +973,7 @@  struct dwc3_scratchpad_array {
  * @regs: base address for our registers
  * @regs_size: address space size
  * @fladj: frame length adjustment
+ * @ref_clk_per: reference clock period configuration
  * @irq_gadget: peripheral controller's IRQ number
  * @otg_irq: IRQ number for OTG IRQs
  * @current_otg_role: current role of operation while using the OTG block
@@ -1141,6 +1146,7 @@  struct dwc3 {
 	struct power_supply	*usb_psy;
 
 	u32			fladj;
+	u32			ref_clk_per;
 	u32			irq_gadget;
 	u32			otg_irq;
 	u32			current_otg_role;