Merge tag 'uniphier-v2019.07' of git://git.denx.de/u-boot-uniphier
[oweals/u-boot.git] / drivers / net / e1000.c
index 1d9f8f3ae2e433610882cb57377b6ffb45240008..a34f69746117651ba938ea0cc968a7b7affe362c 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /**************************************************************************
 Intel Pro 1000 for ppcboot/das-u-boot
 Drivers are port from Intel's Linux driver e1000-4.3.15
@@ -9,7 +10,6 @@ tested on both gig copper and gig fiber boards
 
   Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
 
- * SPDX-License-Identifier:    GPL-2.0+
 
   Contact Information:
   Linux NICS <linux.nics@intel.com>
@@ -1181,7 +1181,7 @@ e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw)
                return;
 
        swsm = E1000_READ_REG(hw, SWSM);
-       if (hw->mac_type == e1000_80003es2lan) {
+       if (hw->mac_type == e1000_80003es2lan || hw->mac_type == e1000_igb) {
                /* Release both semaphores. */
                swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
        } else
@@ -1313,33 +1313,21 @@ static bool e1000_is_second_port(struct e1000_hw *hw)
 
 #ifndef CONFIG_E1000_NO_NVM
 /******************************************************************************
- * Reads the adapter's MAC address from the EEPROM and inverts the LSB for the
- * second function of dual function devices
+ * Reads the adapter's MAC address from the EEPROM
  *
- * nic - Struct containing variables accessed by shared code
+ * hw - Struct containing variables accessed by shared code
+ * enetaddr - buffering where the MAC address will be stored
  *****************************************************************************/
-static int
-e1000_read_mac_addr(struct e1000_hw *hw, unsigned char enetaddr[6])
+static int e1000_read_mac_addr_from_eeprom(struct e1000_hw *hw,
+                                          unsigned char enetaddr[6])
 {
        uint16_t offset;
        uint16_t eeprom_data;
-       uint32_t reg_data = 0;
        int i;
 
-       DEBUGFUNC();
-
        for (i = 0; i < NODE_ADDRESS_SIZE; i += 2) {
                offset = i >> 1;
-               if (hw->mac_type == e1000_igb) {
-                       /* i210 preloads MAC address into RAL/RAH registers */
-                       if (offset == 0)
-                               reg_data = E1000_READ_REG_ARRAY(hw, RA, 0);
-                       else if (offset == 1)
-                               reg_data >>= 16;
-                       else if (offset == 2)
-                               reg_data = E1000_READ_REG_ARRAY(hw, RA, 1);
-                       eeprom_data = reg_data & 0xffff;
-               } else if (e1000_read_eeprom(hw, offset, 1, &eeprom_data) < 0) {
+               if (e1000_read_eeprom(hw, offset, 1, &eeprom_data) < 0) {
                        DEBUGOUT("EEPROM Read Error\n");
                        return -E1000_ERR_EEPROM;
                }
@@ -1347,6 +1335,63 @@ e1000_read_mac_addr(struct e1000_hw *hw, unsigned char enetaddr[6])
                enetaddr[i + 1] = (eeprom_data >> 8) & 0xff;
        }
 
+       return 0;
+}
+
+/******************************************************************************
+ * Reads the adapter's MAC address from the RAL/RAH registers
+ *
+ * hw - Struct containing variables accessed by shared code
+ * enetaddr - buffering where the MAC address will be stored
+ *****************************************************************************/
+static int e1000_read_mac_addr_from_regs(struct e1000_hw *hw,
+                                        unsigned char enetaddr[6])
+{
+       uint16_t offset, tmp;
+       uint32_t reg_data = 0;
+       int i;
+
+       if (hw->mac_type != e1000_igb)
+               return -E1000_ERR_MAC_TYPE;
+
+       for (i = 0; i < NODE_ADDRESS_SIZE; i += 2) {
+               offset = i >> 1;
+
+               if (offset == 0)
+                       reg_data = E1000_READ_REG_ARRAY(hw, RA, 0);
+               else if (offset == 1)
+                       reg_data >>= 16;
+               else if (offset == 2)
+                       reg_data = E1000_READ_REG_ARRAY(hw, RA, 1);
+               tmp = reg_data & 0xffff;
+
+               enetaddr[i] = tmp & 0xff;
+               enetaddr[i + 1] = (tmp >> 8) & 0xff;
+       }
+
+       return 0;
+}
+
+/******************************************************************************
+ * Reads the adapter's MAC address from the EEPROM and inverts the LSB for the
+ * second function of dual function devices
+ *
+ * hw - Struct containing variables accessed by shared code
+ * enetaddr - buffering where the MAC address will be stored
+ *****************************************************************************/
+static int e1000_read_mac_addr(struct e1000_hw *hw, unsigned char enetaddr[6])
+{
+       int ret_val;
+
+       if (hw->mac_type == e1000_igb) {
+               /* i210 preloads MAC address into RAL/RAH registers */
+               ret_val = e1000_read_mac_addr_from_regs(hw, enetaddr);
+       } else {
+               ret_val = e1000_read_mac_addr_from_eeprom(hw, enetaddr);
+       }
+       if (ret_val)
+               return ret_val;
+
        /* Invert the last bit if this is the second device */
        if (e1000_is_second_port(hw))
                enetaddr[5] ^= 1;
@@ -5604,6 +5649,45 @@ e1000_poll(struct eth_device *nic)
        return len ? 1 : 0;
 }
 
+static int e1000_write_hwaddr(struct eth_device *dev)
+{
+#ifndef CONFIG_E1000_NO_NVM
+       unsigned char *mac = dev->enetaddr;
+       unsigned char current_mac[6];
+       struct e1000_hw *hw = dev->priv;
+       uint16_t data[3];
+       int ret_val, i;
+
+       DEBUGOUT("%s: mac=%pM\n", __func__, mac);
+
+       memset(current_mac, 0, 6);
+
+       /* Read from EEPROM, not from registers, to make sure
+        * the address is persistently configured
+        */
+       ret_val = e1000_read_mac_addr_from_eeprom(hw, current_mac);
+       DEBUGOUT("%s: current mac=%pM\n", __func__, current_mac);
+
+       /* Only write to EEPROM if the given address is different or
+        * reading the current address failed
+        */
+       if (!ret_val && memcmp(current_mac, mac, 6) == 0)
+               return 0;
+
+       for (i = 0; i < 3; ++i)
+               data[i] = mac[i * 2 + 1] << 8 | mac[i * 2];
+
+       ret_val = e1000_write_eeprom_srwr(hw, 0x0, 3, data);
+
+       if (!ret_val)
+               ret_val = e1000_update_eeprom_checksum_i210(hw);
+
+       return ret_val;
+#else
+       return 0;
+#endif
+}
+
 /**************************************************************************
 PROBE - Look for an adapter, this routine's visible to the outside
 You should omit the last argument struct pci_device * for a non-PCI NIC
@@ -5653,6 +5737,7 @@ e1000_initialize(bd_t * bis)
                nic->recv = e1000_poll;
                nic->send = e1000_transmit;
                nic->halt = e1000_disable;
+               nic->write_hwaddr = e1000_write_hwaddr;
                eth_register(nic);
        }