On 08/11/2017 16:59, Martyn Welch wrote: > From: Hannu Lounento <[email protected]> > > 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 <[email protected]> > CC: Joe Hershberger <[email protected]> > Signed-off-by: Martyn Welch <[email protected]> > --- > 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 */ >
Reviewed-by: Stefano Babic <[email protected]> Best regards, Stefano -- ===================================================================== DENX Software Engineering GmbH, Managing Director: Wolfgang Denk HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: +49-8142-66989-53 Fax: +49-8142-66989-80 Email: [email protected] ===================================================================== _______________________________________________ U-Boot mailing list [email protected] https://lists.denx.de/listinfo/u-boot

