[U-Boot] [PATCH 02/16] net: e1000: add support for writing to EEPROM

Martyn Welch martyn.welch at collabora.co.uk
Wed Nov 8 15:59:36 UTC 2017


From: Hannu Lounento <hannu.lounento at ge.com>

Port functions for writing to EEPROM, updating the checksum and
committing data to flash from the Linux kernel igb driver.

Functions were ported from Linux 4.8-rc2 (694d0d0bb20).

Signed-off-by: Hannu Lounento <hannu.lounento at ge.com>
CC: Joe Hershberger <joe.hershberger at ni.com>
Signed-off-by: Martyn Welch <martyn.welch at collabora.co.uk>
---
 drivers/net/e1000.c | 171 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 drivers/net/e1000.h |   3 +
 2 files changed, 172 insertions(+), 2 deletions(-)

diff --git a/drivers/net/e1000.c b/drivers/net/e1000.c
index 875682b..7aecdb9 100644
--- a/drivers/net/e1000.c
+++ b/drivers/net/e1000.c
@@ -150,6 +150,7 @@ static int32_t e1000_check_phy_reset_block(struct e1000_hw *hw);
 
 #ifndef CONFIG_E1000_NO_NVM
 static void e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw);
+static int32_t e1000_get_hw_eeprom_semaphore(struct e1000_hw *hw);
 static int32_t e1000_read_eeprom(struct e1000_hw *hw, uint16_t offset,
 		uint16_t words,
 		uint16_t *data);
@@ -862,6 +863,62 @@ e1000_read_eeprom(struct e1000_hw *hw, uint16_t offset,
 }
 
 /******************************************************************************
+ *  e1000_write_eeprom_srwr - Write to Shadow Ram using EEWR
+ *  @hw: pointer to the HW structure
+ *  @offset: offset within the Shadow Ram to be written to
+ *  @words: number of words to write
+ *  @data: 16 bit word(s) to be written to the Shadow Ram
+ *
+ *  Writes data to Shadow Ram at offset using EEWR register.
+ *
+ *  If e1000_update_eeprom_checksum_i210 is not called after this function, the
+ *  Shadow Ram will most likely contain an invalid checksum.
+ *****************************************************************************/
+static int32_t e1000_write_eeprom_srwr(struct e1000_hw *hw, uint16_t offset,
+				       uint16_t words, uint16_t *data)
+{
+	struct e1000_eeprom_info *eeprom = &hw->eeprom;
+	uint32_t i, k, eewr = 0;
+	uint32_t attempts = 100000;
+	int32_t ret_val = 0;
+
+	/* A check for invalid values:  offset too large, too many words,
+	 * too many words for the offset, and not enough words.
+	 */
+	if ((offset >= eeprom->word_size) ||
+	    (words > (eeprom->word_size - offset)) || (words == 0)) {
+		DEBUGOUT("nvm parameter(s) out of bounds\n");
+		ret_val = -E1000_ERR_EEPROM;
+		goto out;
+	}
+
+	for (i = 0; i < words; i++) {
+		eewr = ((offset + i) << E1000_EEPROM_RW_ADDR_SHIFT)
+				| (data[i] << E1000_EEPROM_RW_REG_DATA) |
+				E1000_EEPROM_RW_REG_START;
+
+		E1000_WRITE_REG(hw, I210_EEWR, eewr);
+
+		for (k = 0; k < attempts; k++) {
+			if (E1000_EEPROM_RW_REG_DONE &
+			    E1000_READ_REG(hw, I210_EEWR)) {
+				ret_val = 0;
+				break;
+			}
+			udelay(5);
+		}
+
+		if (ret_val) {
+			DEBUGOUT("Shadow RAM write EEWR timed out\n");
+			break;
+		}
+	}
+
+out:
+	return ret_val;
+}
+
+/******************************************************************************
  * Verifies that the EEPROM has a valid checksum
  *
  * hw - Struct containing variables accessed by shared code
@@ -907,6 +964,116 @@ static int e1000_validate_eeprom_checksum(struct e1000_hw *hw)
 
 	return -E1000_ERR_EEPROM;
 }
+
+/******************************************************************************
+ *  e1000_pool_flash_update_done_i210 - Pool FLUDONE status.
+ *  @hw: pointer to the HW structure
+ *
+ *****************************************************************************/
+static int32_t e1000_pool_flash_update_done_i210(struct e1000_hw *hw)
+{
+	int32_t ret_val = -E1000_ERR_EEPROM;
+	uint32_t i, reg;
+
+	for (i = 0; i < E1000_FLUDONE_ATTEMPTS; i++) {
+		reg = E1000_READ_REG(hw, EECD);
+		if (reg & E1000_EECD_FLUDONE_I210) {
+			ret_val = 0;
+			break;
+		}
+		udelay(5);
+	}
+
+	return ret_val;
+}
+
+/******************************************************************************
+ *  e1000_update_flash_i210 - Commit EEPROM to the flash
+ *  @hw: pointer to the HW structure
+ *
+ *****************************************************************************/
+static int32_t e1000_update_flash_i210(struct e1000_hw *hw)
+{
+	int32_t ret_val = 0;
+	uint32_t flup;
+
+	ret_val = e1000_pool_flash_update_done_i210(hw);
+	if (ret_val == -E1000_ERR_EEPROM) {
+		DEBUGOUT("Flash update time out\n");
+		goto out;
+	}
+
+	flup = E1000_READ_REG(hw, EECD) | E1000_EECD_FLUPD_I210;
+	E1000_WRITE_REG(hw, EECD, flup);
+
+	ret_val = e1000_pool_flash_update_done_i210(hw);
+	if (ret_val)
+		DEBUGOUT("Flash update time out\n");
+	else
+		DEBUGOUT("Flash update complete\n");
+
+out:
+	return ret_val;
+}
+
+/******************************************************************************
+ *  e1000_update_eeprom_checksum_i210 - Update EEPROM checksum
+ *  @hw: pointer to the HW structure
+ *
+ *  Updates the EEPROM checksum by reading/adding each word of the EEPROM
+ *  up to the checksum.  Then calculates the EEPROM checksum and writes the
+ *  value to the EEPROM. Next commit EEPROM data onto the Flash.
+ *****************************************************************************/
+static int32_t e1000_update_eeprom_checksum_i210(struct e1000_hw *hw)
+{
+	int32_t ret_val = 0;
+	uint16_t checksum = 0;
+	uint16_t i, nvm_data;
+
+	/* Read the first word from the EEPROM. If this times out or fails, do
+	 * not continue or we could be in for a very long wait while every
+	 * EEPROM read fails
+	 */
+	ret_val = e1000_read_eeprom_eerd(hw, 0, 1, &nvm_data);
+	if (ret_val) {
+		DEBUGOUT("EEPROM read failed\n");
+		goto out;
+	}
+
+	if (!(e1000_get_hw_eeprom_semaphore(hw))) {
+		/* Do not use hw->nvm.ops.write, hw->nvm.ops.read
+		 * because we do not want to take the synchronization
+		 * semaphores twice here.
+		 */
+
+		for (i = 0; i < EEPROM_CHECKSUM_REG; i++) {
+			ret_val = e1000_read_eeprom_eerd(hw, i, 1, &nvm_data);
+			if (ret_val) {
+				e1000_put_hw_eeprom_semaphore(hw);
+				DEBUGOUT("EEPROM Read Error while updating checksum.\n");
+				goto out;
+			}
+			checksum += nvm_data;
+		}
+		checksum = (uint16_t)EEPROM_SUM - checksum;
+		ret_val = e1000_write_eeprom_srwr(hw, EEPROM_CHECKSUM_REG, 1,
+						  &checksum);
+		if (ret_val) {
+			e1000_put_hw_eeprom_semaphore(hw);
+			DEBUGOUT("EEPROM Write Error while updating checksum.\n");
+			goto out;
+		}
+
+		e1000_put_hw_eeprom_semaphore(hw);
+
+		ret_val = e1000_update_flash_i210(hw);
+	} else {
+		ret_val = -E1000_ERR_SWFW_SYNC;
+	}
+
+out:
+	return ret_val;
+}
 #endif /* CONFIG_E1000_NO_NVM */
 
 /*****************************************************************************
@@ -970,7 +1137,7 @@ e1000_get_software_semaphore(struct e1000_hw *hw)
 
 	DEBUGFUNC();
 
-	if (hw->mac_type != e1000_80003es2lan)
+	if (hw->mac_type != e1000_80003es2lan && hw->mac_type != e1000_igb)
 		return E1000_SUCCESS;
 
 	while (timeout) {
@@ -1044,7 +1211,7 @@ e1000_get_hw_eeprom_semaphore(struct e1000_hw *hw)
 	if (!hw->eeprom_semaphore_present)
 		return E1000_SUCCESS;
 
-	if (hw->mac_type == e1000_80003es2lan) {
+	if (hw->mac_type == e1000_80003es2lan || hw->mac_type == e1000_igb) {
 		/* Get the SW semaphore. */
 		if (e1000_get_software_semaphore(hw) != E1000_SUCCESS)
 			return -E1000_ERR_EEPROM;
diff --git a/drivers/net/e1000.h b/drivers/net/e1000.h
index fcb7df0..6376de1 100644
--- a/drivers/net/e1000.h
+++ b/drivers/net/e1000.h
@@ -1242,6 +1242,9 @@ struct e1000_hw {
 #define E1000_EECD_SELSHAD   0x00020000 /* Select Shadow RAM */
 #define E1000_EECD_INITSRAM  0x00040000 /* Initialize Shadow RAM */
 #define E1000_EECD_FLUPD     0x00080000 /* Update FLASH */
+#define E1000_EECD_FLUPD_I210       0x00800000 /* Update FLASH */
+#define E1000_EECD_FLUDONE_I210     0x04000000 /* Update FLASH done*/
+#define E1000_FLUDONE_ATTEMPTS      20000
 #define E1000_EECD_AUPDEN    0x00100000 /* Enable Autonomous FLASH update */
 #define E1000_EECD_SHADV     0x00200000 /* Shadow RAM Data Valid */
 #define E1000_EECD_SEC1VAL   0x00400000 /* Sector One Valid */
-- 
2.1.4



More information about the U-Boot mailing list