Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0a8b275d authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'lan78xx-Read-configuration-from-Device-Tree'



Phil Elwell says:

====================
lan78xx: Read configuration from Device Tree

The Microchip LAN78XX family of devices are Ethernet controllers with
a USB interface. Despite being discoverable devices it can be useful to
be able to configure them from Device Tree, particularly in low-cost
applications without an EEPROM or programmed OTP.

This patch set adds support for reading the MAC address and LED modes from
Device Tree.

v4:
- Rename nodes in bindings doc.

v3:
- Move LED setting into PHY driver.

v2:
- Use eth_platform_get_mac_address.
- Support up to 4 LEDs, and move LED mode constants into dt-bindings header.
- Improve bindings document.
- Remove EEE support.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents a83762d9 01d26589
Loading
Loading
Loading
Loading
+54 −0
Original line number Diff line number Diff line
Microchip LAN78xx Gigabit Ethernet controller

The LAN78XX devices are usually configured by programming their OTP or with
an external EEPROM, but some platforms (e.g. Raspberry Pi 3 B+) have neither.
The Device Tree properties, if present, override the OTP and EEPROM.

Required properties:
- compatible: Should be one of "usb424,7800", "usb424,7801" or "usb424,7850".

Optional properties:
- local-mac-address:   see ethernet.txt
- mac-address:         see ethernet.txt

Optional properties of the embedded PHY:
- microchip,led-modes: a 0..4 element vector, with each element configuring
  the operating mode of an LED. Omitted LEDs are turned off. Allowed values
  are defined in "include/dt-bindings/net/microchip-lan78xx.h".

Example:

/* Based on the configuration for a Raspberry Pi 3 B+ */
&usb {
	usb-port@1 {
		compatible = "usb424,2514";
		reg = <1>;
		#address-cells = <1>;
		#size-cells = <0>;

		usb-port@1 {
			compatible = "usb424,2514";
			reg = <1>;
			#address-cells = <1>;
			#size-cells = <0>;

			ethernet: ethernet@1 {
				compatible = "usb424,7800";
				reg = <1>;
				local-mac-address = [ 00 11 22 33 44 55 ];

				mdio {
					#address-cells = <0x1>;
					#size-cells = <0x0>;
					eth_phy: ethernet-phy@1 {
						reg = <1>;
						microchip,led-modes = <
							LAN78XX_LINK_1000_ACTIVITY
							LAN78XX_LINK_10_100_ACTIVITY
						>;
					};
				};
			};
		};
	};
};
+2 −0
Original line number Diff line number Diff line
@@ -14571,7 +14571,9 @@ M: Woojung Huh <woojung.huh@microchip.com>
M:	Microchip Linux Driver Support <UNGLinuxDriver@microchip.com>
L:	netdev@vger.kernel.org
S:	Maintained
F:	Documentation/devicetree/bindings/net/microchip,lan78xx.txt
F:	drivers/net/usb/lan78xx.*
F:	include/dt-bindings/net/microchip-lan78xx.h

USB MASS STORAGE DRIVER
M:	Alan Stern <stern@rowland.harvard.edu>
+25 −0
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@
#include <linux/ethtool.h>
#include <linux/phy.h>
#include <linux/microchipphy.h>
#include <linux/of.h>
#include <dt-bindings/net/microchip-lan78xx.h>

#define DRIVER_AUTHOR	"WOOJUNG HUH <woojung.huh@microchip.com>"
#define DRIVER_DESC	"Microchip LAN88XX PHY driver"
@@ -70,6 +72,8 @@ static int lan88xx_probe(struct phy_device *phydev)
{
	struct device *dev = &phydev->mdio.dev;
	struct lan88xx_priv *priv;
	u32 led_modes[4];
	int len;

	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
	if (!priv)
@@ -77,6 +81,27 @@ static int lan88xx_probe(struct phy_device *phydev)

	priv->wolopts = 0;

	len = of_property_read_variable_u32_array(dev->of_node,
						  "microchip,led-modes",
						  led_modes,
						  0,
						  ARRAY_SIZE(led_modes));
	if (len >= 0) {
		u32 reg = 0;
		int i;

		for (i = 0; i < len; i++) {
			if (led_modes[i] > 15)
				return -EINVAL;
			reg |= led_modes[i] << (i * 4);
		}
		for (; i < ARRAY_SIZE(led_modes); i++)
			reg |= LAN78XX_FORCE_LED_OFF << (i * 4);
		(void)phy_write(phydev, LAN78XX_PHY_LED_MODE_SELECT, reg);
	} else if (len == -EOVERFLOW) {
		return -EINVAL;
	}

	/* these values can be used to identify internal PHY */
	priv->chip_id = phy_read_mmd(phydev, 3, LAN88XX_MMD3_CHIP_ID);
	priv->chip_rev = phy_read_mmd(phydev, 3, LAN88XX_MMD3_CHIP_REV);
+51 −23
Original line number Diff line number Diff line
@@ -37,6 +37,8 @@
#include <linux/irqchip/chained_irq.h>
#include <linux/microchipphy.h>
#include <linux/phy.h>
#include <linux/of_mdio.h>
#include <linux/of_net.h>
#include "lan78xx.h"

#define DRIVER_AUTHOR	"WOOJUNG HUH <woojung.huh@microchip.com>"
@@ -1652,12 +1654,15 @@ static void lan78xx_init_mac_address(struct lan78xx_net *dev)
	addr[5] = (addr_hi >> 8) & 0xFF;

	if (!is_valid_ether_addr(addr)) {
		/* reading mac address from EEPROM or OTP */
		if ((lan78xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN,
					 addr) == 0) ||
		    (lan78xx_read_otp(dev, EEPROM_MAC_OFFSET, ETH_ALEN,
				      addr) == 0)) {
			if (is_valid_ether_addr(addr)) {
		if (!eth_platform_get_mac_address(&dev->udev->dev, addr)) {
			/* valid address present in Device Tree */
			netif_dbg(dev, ifup, dev->net,
				  "MAC address read from Device Tree");
		} else if (((lan78xx_read_eeprom(dev, EEPROM_MAC_OFFSET,
						 ETH_ALEN, addr) == 0) ||
			    (lan78xx_read_otp(dev, EEPROM_MAC_OFFSET,
					      ETH_ALEN, addr) == 0)) &&
			   is_valid_ether_addr(addr)) {
			/* eeprom values are valid so use them */
			netif_dbg(dev, ifup, dev->net,
				  "MAC address read from EEPROM");
@@ -1674,12 +1679,6 @@ static void lan78xx_init_mac_address(struct lan78xx_net *dev)

		ret = lan78xx_write_reg(dev, RX_ADDRL, addr_lo);
		ret = lan78xx_write_reg(dev, RX_ADDRH, addr_hi);
		} else {
			/* generate random MAC */
			random_ether_addr(addr);
			netif_dbg(dev, ifup, dev->net,
				  "MAC address set to random addr");
		}
	}

	ret = lan78xx_write_reg(dev, MAF_LO(0), addr_lo);
@@ -1762,6 +1761,7 @@ static int lan78xx_mdiobus_write(struct mii_bus *bus, int phy_id, int idx,

static int lan78xx_mdio_init(struct lan78xx_net *dev)
{
	struct device_node *node;
	int ret;

	dev->mdiobus = mdiobus_alloc();
@@ -1790,7 +1790,13 @@ static int lan78xx_mdio_init(struct lan78xx_net *dev)
		break;
	}

	node = of_get_child_by_name(dev->udev->dev.of_node, "mdio");
	if (node) {
		ret = of_mdiobus_register(dev->mdiobus, node);
		of_node_put(node);
	} else {
		ret = mdiobus_register(dev->mdiobus);
	}
	if (ret) {
		netdev_err(dev->net, "can't register MDIO bus\n");
		goto exit1;
@@ -2079,6 +2085,28 @@ static int lan78xx_phy_init(struct lan78xx_net *dev)
	mii_adv = (u32)mii_advertise_flowctrl(dev->fc_request_control);
	phydev->advertising |= mii_adv_to_ethtool_adv_t(mii_adv);

	if (phydev->mdio.dev.of_node) {
		u32 reg;
		int len;

		len = of_property_count_elems_of_size(phydev->mdio.dev.of_node,
						      "microchip,led-modes",
						      sizeof(u32));
		if (len >= 0) {
			/* Ensure the appropriate LEDs are enabled */
			lan78xx_read_reg(dev, HW_CFG, &reg);
			reg &= ~(HW_CFG_LED0_EN_ |
				 HW_CFG_LED1_EN_ |
				 HW_CFG_LED2_EN_ |
				 HW_CFG_LED3_EN_);
			reg |= (len > 0) * HW_CFG_LED0_EN_ |
				(len > 1) * HW_CFG_LED1_EN_ |
				(len > 2) * HW_CFG_LED2_EN_ |
				(len > 3) * HW_CFG_LED3_EN_;
			lan78xx_write_reg(dev, HW_CFG, reg);
		}
	}

	genphy_config_aneg(phydev);

	dev->fc_autoneg = phydev->autoneg;
+21 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _DT_BINDINGS_MICROCHIP_LAN78XX_H
#define _DT_BINDINGS_MICROCHIP_LAN78XX_H

/* LED modes for LAN7800/LAN7850 embedded PHY */

#define LAN78XX_LINK_ACTIVITY           0
#define LAN78XX_LINK_1000_ACTIVITY      1
#define LAN78XX_LINK_100_ACTIVITY       2
#define LAN78XX_LINK_10_ACTIVITY        3
#define LAN78XX_LINK_100_1000_ACTIVITY  4
#define LAN78XX_LINK_10_1000_ACTIVITY   5
#define LAN78XX_LINK_10_100_ACTIVITY    6
#define LAN78XX_DUPLEX_COLLISION        8
#define LAN78XX_COLLISION               9
#define LAN78XX_ACTIVITY                10
#define LAN78XX_AUTONEG_FAULT           12
#define LAN78XX_FORCE_LED_OFF           14
#define LAN78XX_FORCE_LED_ON            15

#endif
Loading