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 if (of_property_read_bool(dev->dev->of_node, "big-endian")) { 68 u8 *data = (u8 *)dev->eeprom.data; 69 int i; 70 71 /* convert eeprom data in Little Endian */ 72 for (i = 0; i < round_down(len, 2); i += 2) 73 put_unaligned_le16(get_unaligned_be16(&data[i]), 74 &data[i]); 75 } 76 77 #ifdef CONFIG_NL80211_TESTMODE 78 dev->test.mtd_name = devm_kstrdup(dev->dev, part, GFP_KERNEL); 79 dev->test.mtd_offset = offset; 80 #endif 81 82 out_put_node: 83 of_node_put(np); 84 return ret; 85 #else 86 return -ENOENT; 87 #endif 88 } 89 90 void 91 mt76_eeprom_override(struct mt76_dev *dev) 92 { 93 #ifdef CONFIG_OF 94 struct device_node *np = dev->dev->of_node; 95 const u8 *mac = NULL; 96 97 if (np) 98 mac = of_get_mac_address(np); 99 if (!IS_ERR_OR_NULL(mac)) 100 ether_addr_copy(dev->macaddr, mac); 101 #endif 102 103 if (!is_valid_ether_addr(dev->macaddr)) { 104 eth_random_addr(dev->macaddr); 105 dev_info(dev->dev, 106 "Invalid MAC address, using random address %pM\n", 107 dev->macaddr); 108 } 109 } 110 EXPORT_SYMBOL_GPL(mt76_eeprom_override); 111 112 int 113 mt76_eeprom_init(struct mt76_dev *dev, int len) 114 { 115 dev->eeprom.size = len; 116 dev->eeprom.data = devm_kzalloc(dev->dev, len, GFP_KERNEL); 117 if (!dev->eeprom.data) 118 return -ENOMEM; 119 120 return !mt76_get_of_eeprom(dev, len); 121 } 122 EXPORT_SYMBOL_GPL(mt76_eeprom_init); 123