Re: [PATCH v5] net/phy: micrel: Add OF configuration support for ksz9021

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




On Mon, Aug 05, 2013 at 07:04:08AM +0000, Sean Cross wrote:
> Some boards require custom PHY configuration, for example due to trace
> length differences.  Add the ability to configure these registers in
> order to get the PHY to function on boards that need it.
> 
> Because PHYs are auto-detected based on MDIO device IDs, allow PHY
> configuration to be specified in the parent Ethernet device node if no
> PHY device node is present.
> 
> Signed-off-by: Sean Cross <xobs@xxxxxxxxxx>
> ---
>  .../devicetree/bindings/net/micrel-ksz9021.txt     |   49 ++++++++++
>  drivers/net/phy/micrel.c                           |  101 +++++++++++++++++++-
>  2 files changed, 149 insertions(+), 1 deletion(-)
>  create mode 100644 Documentation/devicetree/bindings/net/micrel-ksz9021.txt
> 
> diff --git a/Documentation/devicetree/bindings/net/micrel-ksz9021.txt b/Documentation/devicetree/bindings/net/micrel-ksz9021.txt
> new file mode 100644
> index 0000000..338a7e2
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/net/micrel-ksz9021.txt
> @@ -0,0 +1,49 @@
> +Micrel KSZ9021 Gigabit Ethernet PHY
> +
> +Some boards require special tuning values, particularly when it comes to
> +clock delays.  You can specify clock delay values by adding
> +micrel-specific properties to an Ethernet OF device node.
> +
> +All skew control options are specified in picoseconds.  The minimum
> +value is 0, and the maximum value is 3000.
> +
> +Optional properties:
> + - rxc-skew : Skew control of RXC pad
> + - rxdv-skew : Skew control of RX CTL pad
> + - txc-skew : Skew control of TXC pad
> + - txen-skew : Skew control of TX_CTL pad
> + - rxd0-skew : Skew control of RX data 0 pad
> + - rxd1-skew : Skew control of RX data 1 pad
> + - rxd2-skew : Skew control of RX data 2 pad
> + - rxd3-skew : Skew control of RX data 3 pad
> + - txd0-skew : Skew control of TX data 0 pad
> + - txd1-skew : Skew control of TX data 1 pad
> + - txd2-skew : Skew control of TX data 2 pad
> + - txd3-skew : Skew control of TX data 3 pad
> +
> +Examples:
> +
> +	/* Attach to an Ethernet device with autodetected PHY */
> +	&enet {
> +		rxc-skew = <3000>; // picoseconds
> +		rxdv-skew = <0>;   // picoseconds
> +		txc-skew = <3000>; // picoseconds
> +		txen-skew = <0>;   // picoseconds
> +		status = "okay";
> +	};
> +
> +	/* Attach to an explicitly-specified PHY */
> +	mdio {
> +		phy0: ethernet-phy@0 {
> +			rxc-skew = <3000>; // picoseconds
> +			rxdv-skew = <0>;   // picoseconds
> +			txc-skew = <3000>; // picoseconds
> +			txen-skew = <0>;   // picoseconds
> +			reg = <0>;
> +		};
> +	};
> +	ethernet@70000 {
> +		status = "okay";
> +		phy = <&phy0>;
> +		phy-mode = "rgmii-id";
> +	};
> diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
> index 2510435..3e60ed0 100644
> --- a/drivers/net/phy/micrel.c
> +++ b/drivers/net/phy/micrel.c
> @@ -25,6 +25,7 @@
>  #include <linux/module.h>
>  #include <linux/phy.h>
>  #include <linux/micrel_phy.h>
> +#include <linux/of.h>
>  
>  /* Operation Mode Strap Override */
>  #define MII_KSZPHY_OMSO				0x16
> @@ -53,6 +54,18 @@
>  #define KS8737_CTRL_INT_ACTIVE_HIGH		(1 << 14)
>  #define KSZ8051_RMII_50MHZ_CLK			(1 << 7)
>  
> +/* Write/read to/from extended registers */
> +#define MII_KSZPHY_EXTREG                       0x0b
> +#define KSZPHY_EXTREG_WRITE                     0x8000
> +
> +#define MII_KSZPHY_EXTREG_WRITE                 0x0c
> +#define MII_KSZPHY_EXTREG_READ                  0x0d
> +
> +/* Extended registers */
> +#define MII_KSZPHY_CLK_CONTROL_PAD_SKEW         0x104
> +#define MII_KSZPHY_RX_DATA_PAD_SKEW             0x105
> +#define MII_KSZPHY_TX_DATA_PAD_SKEW             0x106
> +
>  static int ksz_config_flags(struct phy_device *phydev)
>  {
>  	int regval;
> @@ -65,6 +78,20 @@ static int ksz_config_flags(struct phy_device *phydev)
>  	return 0;
>  }
>  
> +static int kszphy_extended_write(struct phy_device *phydev,
> +                                 u32 regnum, u16 val)
> +{
> +	phy_write(phydev, MII_KSZPHY_EXTREG, KSZPHY_EXTREG_WRITE | regnum);
> +	return phy_write(phydev, MII_KSZPHY_EXTREG_WRITE, val);
> +}
> +
> +static int kszphy_extended_read(struct phy_device *phydev,
> +                                 u32 regnum)
> +{
> +	phy_write(phydev, MII_KSZPHY_EXTREG, regnum);
> +	return phy_read(phydev, MII_KSZPHY_EXTREG_READ);
> +}
> +
>  static int kszphy_ack_interrupt(struct phy_device *phydev)
>  {
>  	/* bit[7..0] int status, which is a read and clear register. */
> @@ -141,6 +168,78 @@ static int ks8051_config_init(struct phy_device *phydev)
>  	return rc < 0 ? rc : 0;
>  }
>  
> +static int ksz9021_load_values_from_of(struct phy_device *phydev,
> +				       struct device_node *of_node, u16 reg,
> +				       char *field1, char *field2,
> +				       char *field3, char *field4)
> +{
> +	int val1 = -1;
> +	int val2 = -2;
> +	int val3 = -3;
> +	int val4 = -4;
> +	int newval;
> +	int matches = 0;
> +
> +	if (!of_property_read_u32(of_node, field1, &val1))
> +		matches++;
> +
> +	if (!of_property_read_u32(of_node, field2, &val2))
> +		matches++;
> +
> +	if (!of_property_read_u32(of_node, field3, &val3))
> +		matches++;
> +
> +	if (!of_property_read_u32(of_node, field4, &val4))
> +		matches++;
> +
> +	if (!matches)
> +		return 0;
> +
> +	if (matches < 4)
> +		newval = kszphy_extended_read(phydev, reg);
> +	else
> +		newval = 0;

Just initialize newval with the reset default of this register. It will
make this function easier. Also this two step read from dt and evaluate
afterwards seems unnecessary.

> +
> +	if (val1 != -1)
> +		newval = ((newval & 0xfff0) | ((val1/200)&0xf) << 0);
> +
> +	if (val2 != -1)
> +		newval = ((newval & 0xff0f) | ((val2/200)&0xf) << 4);
> +
> +	if (val3 != -1)
> +		newval = ((newval & 0xf0ff) | ((val3/200)&0xf) << 8);
> +
> +	if (val4 != -1)
> +		newval = ((newval & 0x0fff) | ((val4/200)&0xf) << 12);
> +
> +	return kszphy_extended_write(phydev, reg, newval);
> +}
> +
> +static int ksz9021_config_init(struct phy_device *phydev)
> +{
> +	struct device *dev = &phydev->dev;
> +	struct device_node *of_node = dev->of_node;
> +
> +	if (!of_node && dev->parent->of_node)
> +		of_node = dev->parent->of_node;
> +
> +	if (of_node) {
> +		ksz9021_load_values_from_of(phydev, of_node,
> +				    MII_KSZPHY_CLK_CONTROL_PAD_SKEW,
> +				    "txen-skew", "txc-skew",
> +				    "rxdv-skew", "rxc-skew");
> +		ksz9021_load_values_from_of(phydev, of_node,
> +				    MII_KSZPHY_RX_DATA_PAD_SKEW,
> +				    "rxd0-skew", "rxd1-skew",
> +				    "rxd2-skew", "rxd3-skew");
> +		ksz9021_load_values_from_of(phydev, of_node,
> +				    MII_KSZPHY_TX_DATA_PAD_SKEW,
> +				    "txd0-skew", "txd1-skew",
> +				    "txd2-skew", "txd3-skew");

Are you sure this register exists? It's not mentioned in my datasheet,
only the first two are.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]
  Powered by Linux