diff options
author | Tom Rini <trini@konsulko.com> | 2018-02-04 08:30:13 -0500 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2018-02-04 08:30:13 -0500 |
commit | ab1af91093e3a5e3e86b77ebaf568facd386a1df (patch) | |
tree | aa005b3bd0fd5716d8dd3b69c1c55f14a34f5f9e /drivers/net | |
parent | b2153075f42c2d46d310778e226bcb11f0af47f5 (diff) | |
parent | d1ceb0c4881332cb0586920f0a40f8e4a48d99a9 (diff) |
Merge git://git.denx.de/u-boot-imx
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/e1000.c | 294 | ||||
-rw-r--r-- | drivers/net/e1000.h | 3 | ||||
-rw-r--r-- | drivers/net/fec_mxc.c | 78 |
3 files changed, 322 insertions, 53 deletions
diff --git a/drivers/net/e1000.c b/drivers/net/e1000.c index 875682b1b89..8316854bc17 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); @@ -861,6 +862,174 @@ e1000_read_eeprom(struct e1000_hw *hw, uint16_t offset, return E1000_SUCCESS; } +#ifndef CONFIG_DM_ETH +/****************************************************************************** + * 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; +} + +/****************************************************************************** + * 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 + /****************************************************************************** * Verifies that the EEPROM has a valid checksum * @@ -970,7 +1139,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 +1213,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; @@ -1144,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; } @@ -1178,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; @@ -5435,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 @@ -5484,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); } diff --git a/drivers/net/e1000.h b/drivers/net/e1000.h index fcb7df0d83f..6376de15ada 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 */ diff --git a/drivers/net/fec_mxc.c b/drivers/net/fec_mxc.c index 433e19f0f81..ff7ad91116c 100644 --- a/drivers/net/fec_mxc.c +++ b/drivers/net/fec_mxc.c @@ -284,7 +284,7 @@ static int fec_tx_task_disable(struct fec_priv *fec) static void fec_rbd_init(struct fec_priv *fec, int count, int dsize) { uint32_t size; - uint8_t *data; + ulong data; int i; /* @@ -293,9 +293,9 @@ static void fec_rbd_init(struct fec_priv *fec, int count, int dsize) */ size = roundup(dsize, ARCH_DMA_MINALIGN); for (i = 0; i < count; i++) { - data = (uint8_t *)fec->rbd_base[i].data_pointer; - memset(data, 0, dsize); - flush_dcache_range((uint32_t)data, (uint32_t)data + size); + data = fec->rbd_base[i].data_pointer; + memset((void *)data, 0, dsize); + flush_dcache_range(data, data + size); fec->rbd_base[i].status = FEC_RBD_EMPTY; fec->rbd_base[i].data_length = 0; @@ -305,8 +305,8 @@ static void fec_rbd_init(struct fec_priv *fec, int count, int dsize) fec->rbd_base[i - 1].status = FEC_RBD_WRAP | FEC_RBD_EMPTY; fec->rbd_index = 0; - flush_dcache_range((unsigned)fec->rbd_base, - (unsigned)fec->rbd_base + size); + flush_dcache_range((ulong)fec->rbd_base, + (ulong)fec->rbd_base + size); } /** @@ -323,7 +323,7 @@ static void fec_rbd_init(struct fec_priv *fec, int count, int dsize) */ static void fec_tbd_init(struct fec_priv *fec) { - unsigned addr = (unsigned)fec->tbd_base; + ulong addr = (ulong)fec->tbd_base; unsigned size = roundup(2 * sizeof(struct fec_bd), ARCH_DMA_MINALIGN); @@ -423,7 +423,7 @@ static int fec_open(struct eth_device *edev) struct fec_priv *fec = (struct fec_priv *)edev->priv; #endif int speed; - uint32_t addr, size; + ulong addr, size; int i; debug("fec_open: fec_open(dev)\n"); @@ -439,7 +439,7 @@ static int fec_open(struct eth_device *edev) /* Flush the descriptors into RAM */ size = roundup(FEC_RBD_NUM * sizeof(struct fec_bd), ARCH_DMA_MINALIGN); - addr = (uint32_t)fec->rbd_base; + addr = (ulong)fec->rbd_base; flush_dcache_range(addr, addr + size); #ifdef FEC_QUIRK_ENET_MAC @@ -533,8 +533,9 @@ static int fec_init(struct eth_device *dev, bd_t *bd) #else struct fec_priv *fec = (struct fec_priv *)dev->priv; #endif - uint32_t mib_ptr = (uint32_t)&fec->eth->rmon_t_drop; - int i; + u8 *mib_ptr = (uint8_t *)&fec->eth->rmon_t_drop; + u8 *i; + ulong addr; /* Initialize MAC address */ #ifdef CONFIG_DM_ETH @@ -562,8 +563,8 @@ static int fec_init(struct eth_device *dev, bd_t *bd) writel(0x00000000, &fec->eth->gaddr1); writel(0x00000000, &fec->eth->gaddr2); - /* Do not access reserved register for i.MX6UL */ - if (!is_mx6ul() && !is_mx6ull()) { + /* Do not access reserved register */ + if (!is_mx6ul() && !is_mx6ull() && !is_mx8m()) { /* clear MIB RAM */ for (i = mib_ptr; i <= mib_ptr + 0xfc; i += 4) writel(0, i); @@ -574,8 +575,12 @@ static int fec_init(struct eth_device *dev, bd_t *bd) /* size and address of each buffer */ writel(FEC_MAX_PKT_SIZE, &fec->eth->emrbr); - writel((uint32_t)fec->tbd_base, &fec->eth->etdsr); - writel((uint32_t)fec->rbd_base, &fec->eth->erdsr); + + addr = (ulong)fec->tbd_base; + writel((uint32_t)addr, &fec->eth->etdsr); + + addr = (ulong)fec->rbd_base; + writel((uint32_t)addr, &fec->eth->erdsr); #ifndef CONFIG_PHYLIB if (fec->xcv_type != SEVENWIRE) @@ -640,8 +645,8 @@ static int fec_send(struct eth_device *dev, void *packet, int length) #endif { unsigned int status; - uint32_t size, end; - uint32_t addr; + u32 size; + ulong addr, end; int timeout = FEC_XFER_TIMEOUT; int ret = 0; @@ -672,13 +677,13 @@ static int fec_send(struct eth_device *dev, void *packet, int length) swap_packet((uint32_t *)packet, length); #endif - addr = (uint32_t)packet; + addr = (ulong)packet; end = roundup(addr + length, ARCH_DMA_MINALIGN); addr &= ~(ARCH_DMA_MINALIGN - 1); flush_dcache_range(addr, end); writew(length, &fec->tbd_base[fec->tbd_index].data_length); - writel(addr, &fec->tbd_base[fec->tbd_index].data_pointer); + writel((uint32_t)addr, &fec->tbd_base[fec->tbd_index].data_pointer); /* * update BD's status now @@ -698,7 +703,7 @@ static int fec_send(struct eth_device *dev, void *packet, int length) * can start DMA. */ size = roundup(2 * sizeof(struct fec_bd), ARCH_DMA_MINALIGN); - addr = (uint32_t)fec->tbd_base; + addr = (ulong)fec->tbd_base; flush_dcache_range(addr, addr + size); /* @@ -799,7 +804,7 @@ static int fec_recv(struct eth_device *dev) unsigned long ievent; int frame_length, len = 0; uint16_t bd_status; - uint32_t addr, size, end; + ulong addr, size, end; int i; ALLOC_CACHE_ALIGN_BUFFER(uchar, buff, FEC_MAX_PKT_SIZE); @@ -854,7 +859,7 @@ static int fec_recv(struct eth_device *dev) * the descriptor. The solution is to mark the whole cache line when all * descriptors in the cache line are processed. */ - addr = (uint32_t)rbd; + addr = (ulong)rbd; addr &= ~(ARCH_DMA_MINALIGN - 1); size = roundup(sizeof(struct fec_bd), ARCH_DMA_MINALIGN); invalidate_dcache_range(addr, addr + size); @@ -882,8 +887,8 @@ static int fec_recv(struct eth_device *dev) len = frame_length; } else { if (bd_status & FEC_RBD_ERR) - debug("error frame: 0x%08x 0x%08x\n", - addr, bd_status); + debug("error frame: 0x%08lx 0x%08x\n", + addr, bd_status); } /* @@ -895,7 +900,7 @@ static int fec_recv(struct eth_device *dev) size = RXDESC_PER_CACHELINE - 1; if ((fec->rbd_index & size) == size) { i = fec->rbd_index - size; - addr = (uint32_t)&fec->rbd_base[i]; + addr = (ulong)&fec->rbd_base[i]; for (; i <= fec->rbd_index ; i++) { fec_rbd_clean(i == (FEC_RBD_NUM - 1), &fec->rbd_base[i]); @@ -922,6 +927,7 @@ static int fec_alloc_descs(struct fec_priv *fec) unsigned int size; int i; uint8_t *data; + ulong addr; /* Allocate TX descriptors. */ size = roundup(2 * sizeof(struct fec_bd), ARCH_DMA_MINALIGN); @@ -950,11 +956,12 @@ static int fec_alloc_descs(struct fec_priv *fec) memset(data, 0, size); - fec->rbd_base[i].data_pointer = (uint32_t)data; + addr = (ulong)data; + fec->rbd_base[i].data_pointer = (uint32_t)addr; fec->rbd_base[i].status = FEC_RBD_EMPTY; fec->rbd_base[i].data_length = 0; /* Flush the buffer to memory. */ - flush_dcache_range((uint32_t)data, (uint32_t)data + size); + flush_dcache_range(addr, addr + size); } /* Mark the last RBD to close the ring. */ @@ -966,8 +973,10 @@ static int fec_alloc_descs(struct fec_priv *fec) return 0; err_ring: - for (; i >= 0; i--) - free((void *)fec->rbd_base[i].data_pointer); + for (; i >= 0; i--) { + addr = fec->rbd_base[i].data_pointer; + free((void *)addr); + } free(fec->rbd_base); err_rx: free(fec->tbd_base); @@ -978,9 +987,12 @@ err_tx: static void fec_free_descs(struct fec_priv *fec) { int i; + ulong addr; - for (i = 0; i < FEC_RBD_NUM; i++) - free((void *)fec->rbd_base[i].data_pointer); + for (i = 0; i < FEC_RBD_NUM; i++) { + addr = fec->rbd_base[i].data_pointer; + free((void *)addr); + } free(fec->rbd_base); free(fec->tbd_base); } @@ -995,7 +1007,7 @@ struct mii_dev *fec_get_miibus(uint32_t base_addr, int dev_id) struct fec_priv *priv = dev_get_priv(dev); struct ethernet_regs *eth = priv->eth; #else - struct ethernet_regs *eth = (struct ethernet_regs *)base_addr; + struct ethernet_regs *eth = (struct ethernet_regs *)(ulong)base_addr; #endif struct mii_dev *bus; int ret; @@ -1065,7 +1077,7 @@ static int fec_probe(bd_t *bd, int dev_id, uint32_t base_addr, edev->halt = fec_halt; edev->write_hwaddr = fec_set_hwaddr; - fec->eth = (struct ethernet_regs *)base_addr; + fec->eth = (struct ethernet_regs *)(ulong)base_addr; fec->bd = bd; fec->xcv_type = CONFIG_FEC_XCV_TYPE; |