1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (C) 2019 Microchip Technology Inc. and its subsidiaries 4 * 5 * Author: Tudor Ambarus <tudor.ambarus@microchip.com> 6 */ 7 8#include <common.h> 9#include <dm.h> 10#include <env.h> 11#include <net.h> 12#include <linux/mtd/spi-nor.h> 13#include <netdev.h> 14 15#define ETH_ADDR_SIZE 6 16 17#ifdef CONFIG_SPI_FLASH_SST 18#define SFDP_MICROCHIP_MANUF_ID 0xbf 19#define SFDP_MICROCHIP_MEM_TYPE 0x26 20#define SFDP_MICROCHIP_DEV_ID 0x43 21 22#define SFDP_MICROCHIP_EUI_OFFSET 0x60 23#define SFDP_MICROCHIP_EUI48 0x30 24 25struct sst26vf064beui { 26 u8 manufacturer_id; 27 u8 memory_type; 28 u8 device_id; 29 u8 reserved; 30}; 31 32/** 33 * sst26vf064beui_check() - Check the validity of the EUI-48 information from 34 * the sst26vf064beui SPI NOR Microchip SFDP table. 35 * @manufacturer_sfdp: pointer to the Microchip manufacturer specific SFDP 36 * table. 37 * 38 * Return: 0 on success, -errno otherwise. 39 */ 40static int sst26vf064beui_check(const u8 *manufacturer_sfdp) 41{ 42 struct sst26vf064beui *sst26vf064beui = 43 (struct sst26vf064beui *)manufacturer_sfdp; 44 45 if (sst26vf064beui->manufacturer_id != SFDP_MICROCHIP_MANUF_ID) 46 return -EINVAL; 47 48 if (sst26vf064beui->memory_type != SFDP_MICROCHIP_MEM_TYPE) 49 return -EINVAL; 50 51 if (sst26vf064beui->device_id != SFDP_MICROCHIP_DEV_ID) 52 return -EINVAL; 53 54 /* 55 * Check if the EUI-48 MAC address is programmed in the next six address 56 * locations. 57 */ 58 if (manufacturer_sfdp[SFDP_MICROCHIP_EUI_OFFSET] != 59 SFDP_MICROCHIP_EUI48) 60 return -EINVAL; 61 62 return 0; 63} 64 65/** 66 * sst26vf064beui_get_ethaddr() - Get the ethernet address from the 67 * sst26vf064beui SPI NOR Microchip SFDP table. 68 * @manufacturer_sfdp: pointer to the Microchip manufacturer specific SFDP 69 * table. 70 * @ethaddr: pointer where to fill the ethernet address 71 * @size: size of the ethernet address. 72 * 73 * Return: 0 on success, -errno otherwise. 74 */ 75static int sst26vf064beui_get_ethaddr(const u8 *manufacturer_sfdp, 76 u8 *ethaddr, size_t size) 77{ 78 u64 eui_table[2]; 79 u64 *p = (u64 *)&manufacturer_sfdp[SFDP_MICROCHIP_EUI_OFFSET]; 80 int i, ret; 81 82 ret = sst26vf064beui_check(manufacturer_sfdp); 83 if (ret) 84 return ret; 85 86 for (i = 0; i < 2; i++) 87 eui_table[i] = le64_to_cpu(p[i]); 88 89 /* Ethaddr starts at offset one. */ 90 memcpy(ethaddr, &((u8 *)eui_table)[1], size); 91 92 return 0; 93} 94#endif 95 96/** 97 * at91_spi_nor_set_ethaddr() - Retrieve and set the ethernet address from the 98 * SPI NOR manufacturer specific SFDP table. 99 */ 100void at91_spi_nor_set_ethaddr(void) 101{ 102 struct udevice *dev; 103 struct spi_nor *nor; 104 const char *ethaddr_name = "ethaddr"; 105 u8 ethaddr[ETH_ADDR_SIZE] = {0}; 106 107 if (env_get(ethaddr_name)) 108 return; 109 110 if (uclass_first_device_err(UCLASS_SPI_FLASH, &dev)) 111 return; 112 113 nor = dev_get_uclass_priv(dev); 114 if (!nor) 115 return; 116 117 if (!nor->manufacturer_sfdp) 118 return; 119 120#ifdef CONFIG_SPI_FLASH_SST 121 if (sst26vf064beui_get_ethaddr(nor->manufacturer_sfdp, ethaddr, 122 ETH_ADDR_SIZE)) 123 return; 124#endif 125 126 if (is_valid_ethaddr(ethaddr)) 127 eth_env_set_enetaddr(ethaddr_name, ethaddr); 128} 129