Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * OF helpers for network devices.
0004  *
0005  * Initially copied out of arch/powerpc/kernel/prom_parse.c
0006  */
0007 #include <linux/etherdevice.h>
0008 #include <linux/kernel.h>
0009 #include <linux/of_net.h>
0010 #include <linux/of_platform.h>
0011 #include <linux/phy.h>
0012 #include <linux/export.h>
0013 #include <linux/device.h>
0014 #include <linux/nvmem-consumer.h>
0015 
0016 /**
0017  * of_get_phy_mode - Get phy mode for given device_node
0018  * @np: Pointer to the given device_node
0019  * @interface: Pointer to the result
0020  *
0021  * The function gets phy interface string from property 'phy-mode' or
0022  * 'phy-connection-type'. The index in phy_modes table is set in
0023  * interface and 0 returned. In case of error interface is set to
0024  * PHY_INTERFACE_MODE_NA and an errno is returned, e.g. -ENODEV.
0025  */
0026 int of_get_phy_mode(struct device_node *np, phy_interface_t *interface)
0027 {
0028     const char *pm;
0029     int err, i;
0030 
0031     *interface = PHY_INTERFACE_MODE_NA;
0032 
0033     err = of_property_read_string(np, "phy-mode", &pm);
0034     if (err < 0)
0035         err = of_property_read_string(np, "phy-connection-type", &pm);
0036     if (err < 0)
0037         return err;
0038 
0039     for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++)
0040         if (!strcasecmp(pm, phy_modes(i))) {
0041             *interface = i;
0042             return 0;
0043         }
0044 
0045     return -ENODEV;
0046 }
0047 EXPORT_SYMBOL_GPL(of_get_phy_mode);
0048 
0049 static int of_get_mac_addr(struct device_node *np, const char *name, u8 *addr)
0050 {
0051     struct property *pp = of_find_property(np, name, NULL);
0052 
0053     if (pp && pp->length == ETH_ALEN && is_valid_ether_addr(pp->value)) {
0054         memcpy(addr, pp->value, ETH_ALEN);
0055         return 0;
0056     }
0057     return -ENODEV;
0058 }
0059 
0060 static int of_get_mac_addr_nvmem(struct device_node *np, u8 *addr)
0061 {
0062     struct platform_device *pdev = of_find_device_by_node(np);
0063     struct nvmem_cell *cell;
0064     const void *mac;
0065     size_t len;
0066     int ret;
0067 
0068     /* Try lookup by device first, there might be a nvmem_cell_lookup
0069      * associated with a given device.
0070      */
0071     if (pdev) {
0072         ret = nvmem_get_mac_address(&pdev->dev, addr);
0073         put_device(&pdev->dev);
0074         return ret;
0075     }
0076 
0077     cell = of_nvmem_cell_get(np, "mac-address");
0078     if (IS_ERR(cell))
0079         return PTR_ERR(cell);
0080 
0081     mac = nvmem_cell_read(cell, &len);
0082     nvmem_cell_put(cell);
0083 
0084     if (IS_ERR(mac))
0085         return PTR_ERR(mac);
0086 
0087     if (len != ETH_ALEN || !is_valid_ether_addr(mac)) {
0088         kfree(mac);
0089         return -EINVAL;
0090     }
0091 
0092     memcpy(addr, mac, ETH_ALEN);
0093     kfree(mac);
0094 
0095     return 0;
0096 }
0097 
0098 /**
0099  * of_get_mac_address()
0100  * @np:     Caller's Device Node
0101  * @addr:   Pointer to a six-byte array for the result
0102  *
0103  * Search the device tree for the best MAC address to use.  'mac-address' is
0104  * checked first, because that is supposed to contain to "most recent" MAC
0105  * address. If that isn't set, then 'local-mac-address' is checked next,
0106  * because that is the default address. If that isn't set, then the obsolete
0107  * 'address' is checked, just in case we're using an old device tree. If any
0108  * of the above isn't set, then try to get MAC address from nvmem cell named
0109  * 'mac-address'.
0110  *
0111  * Note that the 'address' property is supposed to contain a virtual address of
0112  * the register set, but some DTS files have redefined that property to be the
0113  * MAC address.
0114  *
0115  * All-zero MAC addresses are rejected, because those could be properties that
0116  * exist in the device tree, but were not set by U-Boot.  For example, the
0117  * DTS could define 'mac-address' and 'local-mac-address', with zero MAC
0118  * addresses.  Some older U-Boots only initialized 'local-mac-address'.  In
0119  * this case, the real MAC is in 'local-mac-address', and 'mac-address' exists
0120  * but is all zeros.
0121  *
0122  * Return: 0 on success and errno in case of error.
0123 */
0124 int of_get_mac_address(struct device_node *np, u8 *addr)
0125 {
0126     int ret;
0127 
0128     if (!np)
0129         return -ENODEV;
0130 
0131     ret = of_get_mac_addr(np, "mac-address", addr);
0132     if (!ret)
0133         return 0;
0134 
0135     ret = of_get_mac_addr(np, "local-mac-address", addr);
0136     if (!ret)
0137         return 0;
0138 
0139     ret = of_get_mac_addr(np, "address", addr);
0140     if (!ret)
0141         return 0;
0142 
0143     return of_get_mac_addr_nvmem(np, addr);
0144 }
0145 EXPORT_SYMBOL(of_get_mac_address);
0146 
0147 /**
0148  * of_get_ethdev_address()
0149  * @np:     Caller's Device Node
0150  * @dev:    Pointer to netdevice which address will be updated
0151  *
0152  * Search the device tree for the best MAC address to use.
0153  * If found set @dev->dev_addr to that address.
0154  *
0155  * See documentation of of_get_mac_address() for more information on how
0156  * the best address is determined.
0157  *
0158  * Return: 0 on success and errno in case of error.
0159  */
0160 int of_get_ethdev_address(struct device_node *np, struct net_device *dev)
0161 {
0162     u8 addr[ETH_ALEN];
0163     int ret;
0164 
0165     ret = of_get_mac_address(np, addr);
0166     if (!ret)
0167         eth_hw_addr_set(dev, addr);
0168     return ret;
0169 }
0170 EXPORT_SYMBOL(of_get_ethdev_address);