^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * OF helpers for network devices.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Initially copied out of arch/powerpc/kernel/prom_parse.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/etherdevice.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/of_net.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/of_platform.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/phy.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/export.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * of_get_phy_mode - Get phy mode for given device_node
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * @np: Pointer to the given device_node
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * @interface: Pointer to the result
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * The function gets phy interface string from property 'phy-mode' or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * 'phy-connection-type'. The index in phy_modes table is set in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * interface and 0 returned. In case of error interface is set to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * PHY_INTERFACE_MODE_NA and an errno is returned, e.g. -ENODEV.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) int of_get_phy_mode(struct device_node *np, phy_interface_t *interface)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) const char *pm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) int err, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) *interface = PHY_INTERFACE_MODE_NA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) err = of_property_read_string(np, "phy-mode", &pm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) err = of_property_read_string(np, "phy-connection-type", &pm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) if (!strcasecmp(pm, phy_modes(i))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) *interface = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) EXPORT_SYMBOL_GPL(of_get_phy_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static const void *of_get_mac_addr(struct device_node *np, const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) struct property *pp = of_find_property(np, name, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) if (pp && pp->length == ETH_ALEN && is_valid_ether_addr(pp->value))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) return pp->value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) static const void *of_get_mac_addr_nvmem(struct device_node *np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) const void *mac;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) u8 nvmem_mac[ETH_ALEN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) struct platform_device *pdev = of_find_device_by_node(np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) if (!pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) return ERR_PTR(-ENODEV);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) ret = nvmem_get_mac_address(&pdev->dev, &nvmem_mac);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) put_device(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) return ERR_PTR(ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) mac = devm_kmemdup(&pdev->dev, nvmem_mac, ETH_ALEN, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) put_device(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) if (!mac)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) return mac;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) * Search the device tree for the best MAC address to use. 'mac-address' is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) * checked first, because that is supposed to contain to "most recent" MAC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) * address. If that isn't set, then 'local-mac-address' is checked next,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) * because that is the default address. If that isn't set, then the obsolete
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) * 'address' is checked, just in case we're using an old device tree. If any
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) * of the above isn't set, then try to get MAC address from nvmem cell named
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) * 'mac-address'.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) * Note that the 'address' property is supposed to contain a virtual address of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) * the register set, but some DTS files have redefined that property to be the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) * MAC address.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) * All-zero MAC addresses are rejected, because those could be properties that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) * exist in the device tree, but were not set by U-Boot. For example, the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) * DTS could define 'mac-address' and 'local-mac-address', with zero MAC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) * addresses. Some older U-Boots only initialized 'local-mac-address'. In
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) * this case, the real MAC is in 'local-mac-address', and 'mac-address' exists
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) * but is all zeros.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) * Return: Will be a valid pointer on success and ERR_PTR in case of error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) const void *of_get_mac_address(struct device_node *np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) const void *addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) addr = of_get_mac_addr(np, "mac-address");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) if (addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) return addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) addr = of_get_mac_addr(np, "local-mac-address");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) if (addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) return addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) addr = of_get_mac_addr(np, "address");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) if (addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) return addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) return of_get_mac_addr_nvmem(np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) EXPORT_SYMBOL(of_get_mac_address);