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

Reply via email to