diff mbox

[v12,1/4] PHY: Add function set_speed to generic PHY framework

Message ID 1393524848-8207-2-git-send-email-lho@apm.com (mailing list archive)
State New, archived
Headers show

Commit Message

Loc Ho Feb. 27, 2014, 6:14 p.m. UTC
This patch adds function set_speed to the generic PHY framework operation
structure. This function can be called to instruct the PHY underlying layer
at specified lane to configure for specified speed in hertz.

Signed-off-by: Loc Ho <lho@apm.com>
---
 drivers/phy/phy-core.c  |   30 ++++++++++++++++++++++++++++++
 include/linux/phy/phy.h |    8 ++++++++
 2 files changed, 38 insertions(+), 0 deletions(-)

Comments

Felipe Balbi Feb. 27, 2014, 7:01 p.m. UTC | #1
Hi,

On Thu, Feb 27, 2014 at 11:14:05AM -0700, Loc Ho wrote:
> This patch adds function set_speed to the generic PHY framework operation
> structure. This function can be called to instruct the PHY underlying layer
> at specified lane to configure for specified speed in hertz.

why ? looks like clk_set_rate() is your friend here. Can you be more
descriptive of the use case ? When will this be used ?
Loc Ho Feb. 27, 2014, 7:57 p.m. UTC | #2
Hi Balbi,

> On Thu, Feb 27, 2014 at 11:14:05AM -0700, Loc Ho wrote:
>> This patch adds function set_speed to the generic PHY framework operation
>> structure. This function can be called to instruct the PHY underlying layer
>> at specified lane to configure for specified speed in hertz.
>
> why ? looks like clk_set_rate() is your friend here. Can you be more
> descriptive of the use case ? When will this be used ?
>

The phy_set_speed is used to configure the operation speed of the PHY
at run-time. The clock interface in general is used to configure the
clock input to the IP. I don't believe they are the same thing. Maybe
it will be clear in my response to your second email

-Loc
Felipe Balbi Feb. 27, 2014, 8:50 p.m. UTC | #3
Hi,

On Thu, Feb 27, 2014 at 11:57:44AM -0800, Loc Ho wrote:
> > On Thu, Feb 27, 2014 at 11:14:05AM -0700, Loc Ho wrote:
> >> This patch adds function set_speed to the generic PHY framework operation
> >> structure. This function can be called to instruct the PHY underlying layer
> >> at specified lane to configure for specified speed in hertz.
> >
> > why ? looks like clk_set_rate() is your friend here. Can you be more
> > descriptive of the use case ? When will this be used ?
> >
> 
> The phy_set_speed is used to configure the operation speed of the PHY
> at run-time. The clock interface in general is used to configure the
> clock input to the IP. I don't believe they are the same thing. Maybe
> it will be clear in my response to your second email

The problem with this is that you end up adding SATA-specific details to
something which is supposed to be generic. After negoatiation, don't you
get any interrupt from your PHY indicating that link speed negotiation
is done ? Or is that IRQ only on AHCI IP ?


cheers
Loc Ho Feb. 27, 2014, 9:09 p.m. UTC | #4
Hi,

>> >> This patch adds function set_speed to the generic PHY framework operation
>> >> structure. This function can be called to instruct the PHY underlying layer
>> >> at specified lane to configure for specified speed in hertz.
>> >
>> > why ? looks like clk_set_rate() is your friend here. Can you be more
>> > descriptive of the use case ? When will this be used ?
>> >
>>
>> The phy_set_speed is used to configure the operation speed of the PHY
>> at run-time. The clock interface in general is used to configure the
>> clock input to the IP. I don't believe they are the same thing. Maybe
>> it will be clear in my response to your second email
>
> The problem with this is that you end up adding SATA-specific details to
> something which is supposed to be generic.

Setting the operation speed is pretty generic from an interface point
of view. An generic multi-purpose PHY can support multiple speed. If
the upper layer wish to operate at an specified speed (say for testing
purpose and etc), it can be allowed.

> After negoatiation, don't you
> get any interrupt from your PHY indicating that link speed negotiation
> is done ? Or is that IRQ only on AHCI IP ?

There is NO interrupt from the PHY. The IRQ is assoicated with the
AHCI IP. With SATA host flow, it starts off with an COMRESET to start
the link negotiation. At that point, it will poll for completion.

Any other concerns?

-Loc
Felipe Balbi Feb. 27, 2014, 9:34 p.m. UTC | #5
Hi,

On Thu, Feb 27, 2014 at 01:09:57PM -0800, Loc Ho wrote:
> >> >> This patch adds function set_speed to the generic PHY framework operation
> >> >> structure. This function can be called to instruct the PHY underlying layer
> >> >> at specified lane to configure for specified speed in hertz.
> >> >
> >> > why ? looks like clk_set_rate() is your friend here. Can you be more
> >> > descriptive of the use case ? When will this be used ?
> >> >
> >>
> >> The phy_set_speed is used to configure the operation speed of the PHY
> >> at run-time. The clock interface in general is used to configure the
> >> clock input to the IP. I don't believe they are the same thing. Maybe
> >> it will be clear in my response to your second email
> >
> > The problem with this is that you end up adding SATA-specific details to
> > something which is supposed to be generic.
> 
> Setting the operation speed is pretty generic from an interface point
> of view. An generic multi-purpose PHY can support multiple speed. If

no it's not. Specially when you consider that your "speed" argument can
be just about anything and depending on the underlying bus, it *will* be
treated differently. Note that e.g. in OMAP devices the exact *same* PHY
IP is used for PCIe, SATA and USB... now, let's assume for the sake of
argument that we were to implement ->set_speed() in that environment,
how do you plan to do that ? a 6MHz arguments isn't valid from USB stand
point and could mean different things in PCIe or SATA.

> the upper layer wish to operate at an specified speed (say for testing
> purpose and etc), it can be allowed.

anything for testing purposes, should be limited to test scenarios.

> > After negoatiation, don't you
> > get any interrupt from your PHY indicating that link speed negotiation
> > is done ? Or is that IRQ only on AHCI IP ?
> 
> There is NO interrupt from the PHY. The IRQ is assoicated with the
> AHCI IP. With SATA host flow, it starts off with an COMRESET to start
> the link negotiation. At that point, it will poll for completion.
> 
> Any other concerns?

hey, calm down... just trying to prevent us from applying something
which isn't truly generic and I don't think "->set_speed" is generic
enough. The semantics of the "speed" argument won't be valid for all use
cases.

I can already see people using that to pass
USB_SPEED_{LOW,FULL,HIGH,SUPER}, instead of actual speed numbers. We wil
end up with a mess to handle from a PHY driver, specially in cases such
as OMAP where, as mentioned above, the same IP is used for SATA, PCIe
and USB3.
Loc Ho Feb. 27, 2014, 10:03 p.m. UTC | #6
HI,

>> >> >> This patch adds function set_speed to the generic PHY framework operation
>> >> >> structure. This function can be called to instruct the PHY underlying layer
>> >> >> at specified lane to configure for specified speed in hertz.
>> >> >
>> >> > why ? looks like clk_set_rate() is your friend here. Can you be more
>> >> > descriptive of the use case ? When will this be used ?
>> >> >
>> >>
>> >> The phy_set_speed is used to configure the operation speed of the PHY
>> >> at run-time. The clock interface in general is used to configure the
>> >> clock input to the IP. I don't believe they are the same thing. Maybe
>> >> it will be clear in my response to your second email
>> >
>> > The problem with this is that you end up adding SATA-specific details to
>> > something which is supposed to be generic.
>>
>> Setting the operation speed is pretty generic from an interface point
>> of view. An generic multi-purpose PHY can support multiple speed. If
>
> no it's not. Specially when you consider that your "speed" argument can
> be just about anything and depending on the underlying bus, it *will* be
> treated differently. Note that e.g. in OMAP devices the exact *same* PHY
> IP is used for PCIe, SATA and USB... now, let's assume for the sake of
> argument that we were to implement ->set_speed() in that environment,
> how do you plan to do that ? a 6MHz arguments isn't valid from USB stand
> point and could mean different things in PCIe or SATA.
>

Correct me if I am wrong here. If the same PHY is used for PCIe, SATA,
and USB, would you not need to indicate what speed the PHY should be
operated at - unless the underlying IP magically negotiate and
configured automatically? If so, what about PHY isn't so intelligent?
How should you suggest that we handle these?

>> the upper layer wish to operate at an specified speed (say for testing
>> purpose and etc), it can be allowed.
>
> anything for testing purposes, should be limited to test scenarios.

Testing purpose is only one use case. Another use case is to limit the
speed so that I can confirm the driver actually works with various
speed of the device and handle correctly.

>
>> > After negoatiation, don't you
>> > get any interrupt from your PHY indicating that link speed negotiation
>> > is done ? Or is that IRQ only on AHCI IP ?
>>
>> There is NO interrupt from the PHY. The IRQ is assoicated with the
>> AHCI IP. With SATA host flow, it starts off with an COMRESET to start
>> the link negotiation. At that point, it will poll for completion.
>>
>> Any other concerns?
>
> hey, calm down... just trying to prevent us from applying something
> which isn't truly generic and I don't think "->set_speed" is generic
> enough. The semantics of the "speed" argument won't be valid for all use
> cases.
>
> I can already see people using that to pass
> USB_SPEED_{LOW,FULL,HIGH,SUPER}, instead of actual speed numbers. We wil
> end up with a mess to handle from a PHY driver, specially in cases such
> as OMAP where, as mentioned above, the same IP is used for SATA, PCIe
> and USB3.
>

This PHY isn't as "intelligent" as other PHY's. What would you suggest
as I need an method to indicate to the underlying PHY that I want to
operate at an specified speed?

-Loc
Loc Ho March 3, 2014, 6:59 a.m. UTC | #7
Hi Felipe and Kishon,

>>> >> >> This patch adds function set_speed to the generic PHY framework operation
>>> >> >> structure. This function can be called to instruct the PHY underlying layer
>>> >> >> at specified lane to configure for specified speed in hertz.
>>> >> >
>>> >> > why ? looks like clk_set_rate() is your friend here. Can you be more
>>> >> > descriptive of the use case ? When will this be used ?
>>> >> >
>>> >>
>>> >> The phy_set_speed is used to configure the operation speed of the PHY
>>> >> at run-time. The clock interface in general is used to configure the
>>> >> clock input to the IP. I don't believe they are the same thing. Maybe
>>> >> it will be clear in my response to your second email
>>> >
>>> > The problem with this is that you end up adding SATA-specific details to
>>> > something which is supposed to be generic.
>>>
>>> Setting the operation speed is pretty generic from an interface point
>>> of view. An generic multi-purpose PHY can support multiple speed. If
>>
>> no it's not. Specially when you consider that your "speed" argument can
>> be just about anything and depending on the underlying bus, it *will* be
>> treated differently. Note that e.g. in OMAP devices the exact *same* PHY
>> IP is used for PCIe, SATA and USB... now, let's assume for the sake of
>> argument that we were to implement ->set_speed() in that environment,
>> how do you plan to do that ? a 6MHz arguments isn't valid from USB stand
>> point and could mean different things in PCIe or SATA.
>>
>
> Correct me if I am wrong here. If the same PHY is used for PCIe, SATA,
> and USB, would you not need to indicate what speed the PHY should be
> operated at - unless the underlying IP magically negotiate and
> configured automatically? If so, what about PHY isn't so intelligent?
> How should you suggest that we handle these?
>
>>> the upper layer wish to operate at an specified speed (say for testing
>>> purpose and etc), it can be allowed.
>>
>> anything for testing purposes, should be limited to test scenarios.
>
> Testing purpose is only one use case. Another use case is to limit the
> speed so that I can confirm the driver actually works with various
> speed of the device and handle correctly.
>
>>
>>> > After negoatiation, don't you
>>> > get any interrupt from your PHY indicating that link speed negotiation
>>> > is done ? Or is that IRQ only on AHCI IP ?
>>>
>>> There is NO interrupt from the PHY. The IRQ is assoicated with the
>>> AHCI IP. With SATA host flow, it starts off with an COMRESET to start
>>> the link negotiation. At that point, it will poll for completion.
>>>
>>> Any other concerns?
>>
>> hey, calm down... just trying to prevent us from applying something
>> which isn't truly generic and I don't think "->set_speed" is generic
>> enough. The semantics of the "speed" argument won't be valid for all use
>> cases.
>>
>> I can already see people using that to pass
>> USB_SPEED_{LOW,FULL,HIGH,SUPER}, instead of actual speed numbers. We wil
>> end up with a mess to handle from a PHY driver, specially in cases such
>> as OMAP where, as mentioned above, the same IP is used for SATA, PCIe
>> and USB3.
>>
>
> This PHY isn't as "intelligent" as other PHY's. What would you suggest
> as I need an method to indicate to the underlying PHY that I want to
> operate at an specified speed?

Sorry if I am pinging you guys too fast here. I am look from an
solution and open to any solution in which it is acceptable for your
original intent of the generic PHY framework. I understand that you
don't believe set_speed is generic enough and may not apply to omap.
Or if you prefer we can try changing the init function to take an
initial MAX speed?

-Loc
Loc Ho March 5, 2014, 9:27 p.m. UTC | #8
Hi,

>>>> >> >> This patch adds function set_speed to the generic PHY framework operation
>>>> >> >> structure. This function can be called to instruct the PHY underlying layer
>>>> >> >> at specified lane to configure for specified speed in hertz.
>>>> >> >
>>>> >> > why ? looks like clk_set_rate() is your friend here. Can you be more
>>>> >> > descriptive of the use case ? When will this be used ?
>>>> >> >
>>>> >>
>>>> >> The phy_set_speed is used to configure the operation speed of the PHY
>>>> >> at run-time. The clock interface in general is used to configure the
>>>> >> clock input to the IP. I don't believe they are the same thing. Maybe
>>>> >> it will be clear in my response to your second email
>>>> >
>>>> > The problem with this is that you end up adding SATA-specific details to
>>>> > something which is supposed to be generic.
>>>>
>>>> Setting the operation speed is pretty generic from an interface point
>>>> of view. An generic multi-purpose PHY can support multiple speed. If
>>>
>>> no it's not. Specially when you consider that your "speed" argument can
>>> be just about anything and depending on the underlying bus, it *will* be
>>> treated differently. Note that e.g. in OMAP devices the exact *same* PHY
>>> IP is used for PCIe, SATA and USB... now, let's assume for the sake of
>>> argument that we were to implement ->set_speed() in that environment,
>>> how do you plan to do that ? a 6MHz arguments isn't valid from USB stand
>>> point and could mean different things in PCIe or SATA.
>>>
>>
>> Correct me if I am wrong here. If the same PHY is used for PCIe, SATA,
>> and USB, would you not need to indicate what speed the PHY should be
>> operated at - unless the underlying IP magically negotiate and
>> configured automatically? If so, what about PHY isn't so intelligent?
>> How should you suggest that we handle these?
>>
>>>> the upper layer wish to operate at an specified speed (say for testing
>>>> purpose and etc), it can be allowed.
>>>
>>> anything for testing purposes, should be limited to test scenarios.
>>
>> Testing purpose is only one use case. Another use case is to limit the
>> speed so that I can confirm the driver actually works with various
>> speed of the device and handle correctly.
>>
>>>
>>>> > After negoatiation, don't you
>>>> > get any interrupt from your PHY indicating that link speed negotiation
>>>> > is done ? Or is that IRQ only on AHCI IP ?
>>>>
>>>> There is NO interrupt from the PHY. The IRQ is assoicated with the
>>>> AHCI IP. With SATA host flow, it starts off with an COMRESET to start
>>>> the link negotiation. At that point, it will poll for completion.
>>>>
>>>> Any other concerns?
>>>
>>> hey, calm down... just trying to prevent us from applying something
>>> which isn't truly generic and I don't think "->set_speed" is generic
>>> enough. The semantics of the "speed" argument won't be valid for all use
>>> cases.
>>>
>>> I can already see people using that to pass
>>> USB_SPEED_{LOW,FULL,HIGH,SUPER}, instead of actual speed numbers. We wil
>>> end up with a mess to handle from a PHY driver, specially in cases such
>>> as OMAP where, as mentioned above, the same IP is used for SATA, PCIe
>>> and USB3.
>>>
>>
>> This PHY isn't as "intelligent" as other PHY's. What would you suggest
>> as I need an method to indicate to the underlying PHY that I want to
>> operate at an specified speed?
>
> Sorry if I am pinging you guys too fast here. I am look from an
> solution and open to any solution in which it is acceptable for your
> original intent of the generic PHY framework. I understand that you
> don't believe set_speed is generic enough and may not apply to omap.
> Or if you prefer we can try changing the init function to take an
> initial MAX speed?
>

For the initial version, I will remove support for Gen1/Gen2 until we
come up with an solution. Then post patches that will address
individual errata's.

-Loc
diff mbox

Patch

diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
index 645c867..5451b6d 100644
--- a/drivers/phy/phy-core.c
+++ b/drivers/phy/phy-core.c
@@ -258,6 +258,36 @@  int phy_power_off(struct phy *phy)
 EXPORT_SYMBOL_GPL(phy_power_off);
 
 /**
+ * phy_set_speed - set an specified lane at an specified speed
+ * @phy: phy instance to be set
+ * @lane: zero-based lane index
+ * @speed: operating speed in hz
+ *
+ * Returns 0 if successful, -ENOTSUPP if not supported,
+ * -EINVAL if parameter out of range.
+ */
+int phy_set_speed(struct phy *phy, int lane, u64 speed)
+{
+        int ret = -ENOTSUPP;
+
+        mutex_lock(&phy->mutex);
+        if (phy->ops->set_speed) {
+                ret =  phy->ops->set_speed(phy, lane, speed);
+                if (ret < 0) {
+                        dev_err(&phy->dev, "phy set speed failed --> %d\n",
+                                ret);
+                        goto out;
+                }
+        }
+
+out:
+        mutex_unlock(&phy->mutex);
+
+        return ret;
+}
+EXPORT_SYMBOL_GPL(phy_set_speed);
+
+/**
  * of_phy_get() - lookup and obtain a reference to a phy by phandle
  * @dev: device that requests this phy
  * @index: the index of the phy
diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h
index e273e5a..4eb589c 100644
--- a/include/linux/phy/phy.h
+++ b/include/linux/phy/phy.h
@@ -27,6 +27,7 @@  struct phy;
  * @exit: operation to be performed while exiting
  * @power_on: powering on the phy
  * @power_off: powering off the phy
+ * @set_speed: set operation speed in hz
  * @owner: the module owner containing the ops
  */
 struct phy_ops {
@@ -34,6 +35,7 @@  struct phy_ops {
 	int	(*exit)(struct phy *phy);
 	int	(*power_on)(struct phy *phy);
 	int	(*power_off)(struct phy *phy);
+	int	(*set_speed)(struct phy *phy, int lane, u64 speed);
 	struct module *owner;
 };
 
@@ -145,6 +147,7 @@  static inline void phy_set_bus_width(struct phy *phy, int bus_width)
 {
 	phy->attrs.bus_width = bus_width;
 }
+int phy_set_speed(struct phy *phy, int lane, u64 speed);
 struct phy *phy_get(struct device *dev, const char *string);
 struct phy *devm_phy_get(struct device *dev, const char *string);
 void phy_put(struct phy *phy);
@@ -227,6 +230,11 @@  static inline void phy_set_bus_width(struct phy *phy, int bus_width)
 	return;
 }
 
+static inline int phy_set_speed(struct phy *phy, int lane, u64 speed)
+{
+	return -ENOSYS;
+}
+
 static inline struct phy *phy_get(struct device *dev, const char *string)
 {
 	return ERR_PTR(-ENOSYS);