1 // SPDX-License-Identifier: ISC 2 /* 3 * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> 4 */ 5 #include <linux/of.h> 6 #include <linux/of_net.h> 7 #include <linux/mtd/mtd.h> 8 #include <linux/mtd/partitions.h> 9 #include <linux/etherdevice.h> 10 #include "mt76.h" 11 12 static int 13 mt76_get_of_eeprom(struct mt76_dev *dev, int len) 14 { 15 #if defined(CONFIG_OF) && defined(CONFIG_MTD) 16 struct device_node *np = dev->dev->of_node; 17 struct mtd_info *mtd; 18 const __be32 *list; 19 const char *part; 20 phandle phandle; 21 int offset = 0; 22 int size; 23 size_t retlen; 24 int ret; 25 26 if (!np) 27 return -ENOENT; 28 29 list = of_get_property(np, "mediatek,mtd-eeprom", &size); 30 if (!list) 31 return -ENOENT; 32 33 phandle = be32_to_cpup(list++); 34 if (!phandle) 35 return -ENOENT; 36 37 np = of_find_node_by_phandle(phandle); 38 if (!np) 39 return -EINVAL; 40 41 part = of_get_property(np, "label", NULL); 42 if (!part) 43 part = np->name; 44 45 mtd = get_mtd_device_nm(part); 46 if (IS_ERR(mtd)) { 47 ret = PTR_ERR(mtd); 48 goto out_put_node; 49 } 50 51 if (size <= sizeof(*list)) { 52 ret = -EINVAL; 53 goto out_put_node; 54 } 55 56 offset = be32_to_cpup(list); 57 ret = mtd_read(mtd, offset, len, &retlen, dev->eeprom.data); 58 put_mtd_device(mtd); 59 if (ret) 60 goto out_put_node; 61 62 if (retlen < len) { 63 ret = -EINVAL; 64 goto out_put_node; 65 } 66 67 out_put_node: 68 of_node_put(np); 69 return ret; 70 #else 71 return -ENOENT; 72 #endif 73 } 74 75 void 76 mt76_eeprom_override(struct mt76_dev *dev) 77 { 78 #ifdef CONFIG_OF 79 struct device_node *np = dev->dev->of_node; 80 const u8 *mac; 81 82 if (!np) 83 return; 84 85 mac = of_get_mac_address(np); 86 if (!IS_ERR(mac)) 87 ether_addr_copy(dev->macaddr, mac); 88 #endif 89 90 if (!is_valid_ether_addr(dev->macaddr)) { 91 eth_random_addr(dev->macaddr); 92 dev_info(dev->dev, 93 "Invalid MAC address, using random address %pM\n", 94 dev->macaddr); 95 } 96 } 97 EXPORT_SYMBOL_GPL(mt76_eeprom_override); 98 99 int 100 mt76_eeprom_init(struct mt76_dev *dev, int len) 101 { 102 dev->eeprom.size = len; 103 dev->eeprom.data = devm_kzalloc(dev->dev, len, GFP_KERNEL); 104 if (!dev->eeprom.data) 105 return -ENOMEM; 106 107 return !mt76_get_of_eeprom(dev, len); 108 } 109 EXPORT_SYMBOL_GPL(mt76_eeprom_init); 110