1 /* 2 * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 #include <linux/of.h> 17 #include <linux/of_net.h> 18 #include <linux/mtd/mtd.h> 19 #include <linux/mtd/partitions.h> 20 #include <linux/etherdevice.h> 21 #include "mt76.h" 22 23 static int 24 mt76_get_of_eeprom(struct mt76_dev *dev, int len) 25 { 26 #if defined(CONFIG_OF) && defined(CONFIG_MTD) 27 struct device_node *np = dev->dev->of_node; 28 struct mtd_info *mtd; 29 const __be32 *list; 30 const char *part; 31 phandle phandle; 32 int offset = 0; 33 int size; 34 size_t retlen; 35 int ret; 36 37 if (!np) 38 return -ENOENT; 39 40 list = of_get_property(np, "mediatek,mtd-eeprom", &size); 41 if (!list) 42 return -ENOENT; 43 44 phandle = be32_to_cpup(list++); 45 if (!phandle) 46 return -ENOENT; 47 48 np = of_find_node_by_phandle(phandle); 49 if (!np) 50 return -EINVAL; 51 52 part = of_get_property(np, "label", NULL); 53 if (!part) 54 part = np->name; 55 56 mtd = get_mtd_device_nm(part); 57 if (IS_ERR(mtd)) 58 return PTR_ERR(mtd); 59 60 if (size <= sizeof(*list)) 61 return -EINVAL; 62 63 offset = be32_to_cpup(list); 64 ret = mtd_read(mtd, offset, len, &retlen, dev->eeprom.data); 65 put_mtd_device(mtd); 66 if (ret) 67 return ret; 68 69 if (retlen < len) 70 return -EINVAL; 71 72 return 0; 73 #else 74 return -ENOENT; 75 #endif 76 } 77 78 void 79 mt76_eeprom_override(struct mt76_dev *dev) 80 { 81 #ifdef CONFIG_OF 82 struct device_node *np = dev->dev->of_node; 83 const u8 *mac; 84 85 if (!np) 86 return; 87 88 mac = of_get_mac_address(np); 89 if (mac) 90 memcpy(dev->macaddr, mac, ETH_ALEN); 91 #endif 92 93 if (!is_valid_ether_addr(dev->macaddr)) { 94 eth_random_addr(dev->macaddr); 95 dev_info(dev->dev, 96 "Invalid MAC address, using random address %pM\n", 97 dev->macaddr); 98 } 99 } 100 EXPORT_SYMBOL_GPL(mt76_eeprom_override); 101 102 int 103 mt76_eeprom_init(struct mt76_dev *dev, int len) 104 { 105 dev->eeprom.size = len; 106 dev->eeprom.data = devm_kzalloc(dev->dev, len, GFP_KERNEL); 107 if (!dev->eeprom.data) 108 return -ENOMEM; 109 110 return !mt76_get_of_eeprom(dev, len); 111 } 112 EXPORT_SYMBOL_GPL(mt76_eeprom_init); 113