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 ret = PTR_ERR(mtd); 59 goto out_put_node; 60 } 61 62 if (size <= sizeof(*list)) { 63 ret = -EINVAL; 64 goto out_put_node; 65 } 66 67 offset = be32_to_cpup(list); 68 ret = mtd_read(mtd, offset, len, &retlen, dev->eeprom.data); 69 put_mtd_device(mtd); 70 if (ret) 71 goto out_put_node; 72 73 if (retlen < len) { 74 ret = -EINVAL; 75 goto out_put_node; 76 } 77 78 out_put_node: 79 of_node_put(np); 80 return ret; 81 #else 82 return -ENOENT; 83 #endif 84 } 85 86 void 87 mt76_eeprom_override(struct mt76_dev *dev) 88 { 89 #ifdef CONFIG_OF 90 struct device_node *np = dev->dev->of_node; 91 const u8 *mac; 92 93 if (!np) 94 return; 95 96 mac = of_get_mac_address(np); 97 if (mac) 98 memcpy(dev->macaddr, mac, ETH_ALEN); 99 #endif 100 101 if (!is_valid_ether_addr(dev->macaddr)) { 102 eth_random_addr(dev->macaddr); 103 dev_info(dev->dev, 104 "Invalid MAC address, using random address %pM\n", 105 dev->macaddr); 106 } 107 } 108 EXPORT_SYMBOL_GPL(mt76_eeprom_override); 109 110 int 111 mt76_eeprom_init(struct mt76_dev *dev, int len) 112 { 113 dev->eeprom.size = len; 114 dev->eeprom.data = devm_kzalloc(dev->dev, len, GFP_KERNEL); 115 if (!dev->eeprom.data) 116 return -ENOMEM; 117 118 return !mt76_get_of_eeprom(dev, len); 119 } 120 EXPORT_SYMBOL_GPL(mt76_eeprom_init); 121