1f501a195SJiawen Wu /* SPDX-License-Identifier: BSD-3-Clause
2f501a195SJiawen Wu * Copyright(c) 2018-2021 Beijing WangXun Technology Co., Ltd.
3f501a195SJiawen Wu * Copyright(c) 2010-2017 Intel Corporation
4f501a195SJiawen Wu */
5f501a195SJiawen Wu
6f501a195SJiawen Wu #include "ngbe_hw.h"
7f501a195SJiawen Wu #include "ngbe_mng.h"
8f501a195SJiawen Wu #include "ngbe_eeprom.h"
9f501a195SJiawen Wu
10f501a195SJiawen Wu /**
11f501a195SJiawen Wu * ngbe_init_eeprom_params - Initialize EEPROM params
12f501a195SJiawen Wu * @hw: pointer to hardware structure
13f501a195SJiawen Wu *
14f501a195SJiawen Wu * Initializes the EEPROM parameters ngbe_rom_info within the
15f501a195SJiawen Wu * ngbe_hw struct in order to set up EEPROM access.
16f501a195SJiawen Wu **/
ngbe_init_eeprom_params(struct ngbe_hw * hw)17f501a195SJiawen Wu s32 ngbe_init_eeprom_params(struct ngbe_hw *hw)
18f501a195SJiawen Wu {
19f501a195SJiawen Wu struct ngbe_rom_info *eeprom = &hw->rom;
20f501a195SJiawen Wu u32 eec;
21f501a195SJiawen Wu u16 eeprom_size;
22f501a195SJiawen Wu
23f501a195SJiawen Wu if (eeprom->type != ngbe_eeprom_unknown)
24f501a195SJiawen Wu return 0;
25f501a195SJiawen Wu
26f501a195SJiawen Wu eeprom->type = ngbe_eeprom_none;
27f501a195SJiawen Wu /* Set default semaphore delay to 10ms which is a well
28f501a195SJiawen Wu * tested value
29f501a195SJiawen Wu */
30f501a195SJiawen Wu eeprom->semaphore_delay = 10; /*ms*/
31f501a195SJiawen Wu /* Clear EEPROM page size, it will be initialized as needed */
32f501a195SJiawen Wu eeprom->word_page_size = 0;
33f501a195SJiawen Wu
34f501a195SJiawen Wu /*
35f501a195SJiawen Wu * Check for EEPROM present first.
36f501a195SJiawen Wu * If not present leave as none
37f501a195SJiawen Wu */
38f501a195SJiawen Wu eec = rd32(hw, NGBE_SPISTAT);
39f501a195SJiawen Wu if (!(eec & NGBE_SPISTAT_BPFLASH)) {
40f501a195SJiawen Wu eeprom->type = ngbe_eeprom_flash;
41f501a195SJiawen Wu
42f501a195SJiawen Wu /*
43f501a195SJiawen Wu * SPI EEPROM is assumed here. This code would need to
44f501a195SJiawen Wu * change if a future EEPROM is not SPI.
45f501a195SJiawen Wu */
46f501a195SJiawen Wu eeprom_size = 4096;
47f501a195SJiawen Wu eeprom->word_size = eeprom_size >> 1;
48f501a195SJiawen Wu }
49f501a195SJiawen Wu
50f501a195SJiawen Wu eeprom->address_bits = 16;
51f501a195SJiawen Wu eeprom->sw_addr = 0x80;
52f501a195SJiawen Wu
53*c811e6a4SJiawen Wu DEBUGOUT("eeprom params: type = %d, size = %d, address bits: %d %d",
54*c811e6a4SJiawen Wu eeprom->type, eeprom->word_size,
55f501a195SJiawen Wu eeprom->address_bits, eeprom->sw_addr);
56f501a195SJiawen Wu
57f501a195SJiawen Wu return 0;
58f501a195SJiawen Wu }
59f501a195SJiawen Wu
60f501a195SJiawen Wu /**
61f501a195SJiawen Wu * ngbe_get_eeprom_semaphore - Get hardware semaphore
62f501a195SJiawen Wu * @hw: pointer to hardware structure
63f501a195SJiawen Wu *
64f501a195SJiawen Wu * Sets the hardware semaphores so EEPROM access can occur for bit-bang method
65f501a195SJiawen Wu **/
ngbe_get_eeprom_semaphore(struct ngbe_hw * hw)66f501a195SJiawen Wu s32 ngbe_get_eeprom_semaphore(struct ngbe_hw *hw)
67f501a195SJiawen Wu {
68f501a195SJiawen Wu s32 status = NGBE_ERR_EEPROM;
69f501a195SJiawen Wu u32 timeout = 2000;
70f501a195SJiawen Wu u32 i;
71f501a195SJiawen Wu u32 swsm;
72f501a195SJiawen Wu
73f501a195SJiawen Wu /* Get SMBI software semaphore between device drivers first */
74f501a195SJiawen Wu for (i = 0; i < timeout; i++) {
75f501a195SJiawen Wu /*
76f501a195SJiawen Wu * If the SMBI bit is 0 when we read it, then the bit will be
77f501a195SJiawen Wu * set and we have the semaphore
78f501a195SJiawen Wu */
79f501a195SJiawen Wu swsm = rd32(hw, NGBE_SWSEM);
80f501a195SJiawen Wu if (!(swsm & NGBE_SWSEM_PF)) {
81f501a195SJiawen Wu status = 0;
82f501a195SJiawen Wu break;
83f501a195SJiawen Wu }
84f501a195SJiawen Wu usec_delay(50);
85f501a195SJiawen Wu }
86f501a195SJiawen Wu
87f501a195SJiawen Wu if (i == timeout) {
88*c811e6a4SJiawen Wu DEBUGOUT("Driver can't access the eeprom - SMBI Semaphore not granted.");
89f501a195SJiawen Wu /*
90f501a195SJiawen Wu * this release is particularly important because our attempts
91f501a195SJiawen Wu * above to get the semaphore may have succeeded, and if there
92f501a195SJiawen Wu * was a timeout, we should unconditionally clear the semaphore
93f501a195SJiawen Wu * bits to free the driver to make progress
94f501a195SJiawen Wu */
95f501a195SJiawen Wu ngbe_release_eeprom_semaphore(hw);
96f501a195SJiawen Wu
97f501a195SJiawen Wu usec_delay(50);
98f501a195SJiawen Wu /*
99f501a195SJiawen Wu * one last try
100f501a195SJiawen Wu * If the SMBI bit is 0 when we read it, then the bit will be
101f501a195SJiawen Wu * set and we have the semaphore
102f501a195SJiawen Wu */
103f501a195SJiawen Wu swsm = rd32(hw, NGBE_SWSEM);
104f501a195SJiawen Wu if (!(swsm & NGBE_SWSEM_PF))
105f501a195SJiawen Wu status = 0;
106f501a195SJiawen Wu }
107f501a195SJiawen Wu
108f501a195SJiawen Wu return status;
109f501a195SJiawen Wu }
110f501a195SJiawen Wu
111f501a195SJiawen Wu /**
112f501a195SJiawen Wu * ngbe_release_eeprom_semaphore - Release hardware semaphore
113f501a195SJiawen Wu * @hw: pointer to hardware structure
114f501a195SJiawen Wu *
115f501a195SJiawen Wu * This function clears hardware semaphore bits.
116f501a195SJiawen Wu **/
ngbe_release_eeprom_semaphore(struct ngbe_hw * hw)117f501a195SJiawen Wu void ngbe_release_eeprom_semaphore(struct ngbe_hw *hw)
118f501a195SJiawen Wu {
119f501a195SJiawen Wu wr32m(hw, NGBE_SWSEM, NGBE_SWSEM_PF, 0);
120f501a195SJiawen Wu ngbe_flush(hw);
121f501a195SJiawen Wu }
122f501a195SJiawen Wu
123f501a195SJiawen Wu /**
1249459ea29SJiawen Wu * ngbe_ee_read_buffer- Read EEPROM word(s) using hostif
1259459ea29SJiawen Wu * @hw: pointer to hardware structure
1269459ea29SJiawen Wu * @offset: offset of word in the EEPROM to read
1279459ea29SJiawen Wu * @words: number of words
1289459ea29SJiawen Wu * @data: word(s) read from the EEPROM
1299459ea29SJiawen Wu *
1309459ea29SJiawen Wu * Reads a 16 bit word(s) from the EEPROM using the hostif.
1319459ea29SJiawen Wu **/
ngbe_ee_readw_buffer(struct ngbe_hw * hw,u32 offset,u32 words,void * data)1329459ea29SJiawen Wu s32 ngbe_ee_readw_buffer(struct ngbe_hw *hw,
1339459ea29SJiawen Wu u32 offset, u32 words, void *data)
1349459ea29SJiawen Wu {
1359459ea29SJiawen Wu const u32 mask = NGBE_MNGSEM_SWMBX | NGBE_MNGSEM_SWFLASH;
1369459ea29SJiawen Wu u32 addr = (offset << 1);
1379459ea29SJiawen Wu u32 len = (words << 1);
1389459ea29SJiawen Wu u8 *buf = (u8 *)data;
1399459ea29SJiawen Wu int err;
1409459ea29SJiawen Wu
1419459ea29SJiawen Wu err = hw->mac.acquire_swfw_sync(hw, mask);
1429459ea29SJiawen Wu if (err)
1439459ea29SJiawen Wu return err;
1449459ea29SJiawen Wu
1459459ea29SJiawen Wu while (len) {
1469459ea29SJiawen Wu u32 seg = (len <= NGBE_PMMBX_DATA_SIZE
1479459ea29SJiawen Wu ? len : NGBE_PMMBX_DATA_SIZE);
1489459ea29SJiawen Wu
1499459ea29SJiawen Wu err = ngbe_hic_sr_read(hw, addr, buf, seg);
1509459ea29SJiawen Wu if (err)
1519459ea29SJiawen Wu break;
1529459ea29SJiawen Wu
1539459ea29SJiawen Wu len -= seg;
1549459ea29SJiawen Wu addr += seg;
1559459ea29SJiawen Wu buf += seg;
1569459ea29SJiawen Wu }
1579459ea29SJiawen Wu
1589459ea29SJiawen Wu hw->mac.release_swfw_sync(hw, mask);
1599459ea29SJiawen Wu return err;
1609459ea29SJiawen Wu }
1619459ea29SJiawen Wu
1629459ea29SJiawen Wu /**
163506abd4aSJiawen Wu * ngbe_ee_read32 - Read EEPROM word using a host interface cmd
164506abd4aSJiawen Wu * @hw: pointer to hardware structure
165506abd4aSJiawen Wu * @offset: offset of word in the EEPROM to read
166506abd4aSJiawen Wu * @data: word read from the EEPROM
167506abd4aSJiawen Wu *
168506abd4aSJiawen Wu * Reads a 32 bit word from the EEPROM using the hostif.
169506abd4aSJiawen Wu **/
ngbe_ee_read32(struct ngbe_hw * hw,u32 addr,u32 * data)170506abd4aSJiawen Wu s32 ngbe_ee_read32(struct ngbe_hw *hw, u32 addr, u32 *data)
171506abd4aSJiawen Wu {
172506abd4aSJiawen Wu const u32 mask = NGBE_MNGSEM_SWMBX | NGBE_MNGSEM_SWFLASH;
173506abd4aSJiawen Wu int err;
174506abd4aSJiawen Wu
175506abd4aSJiawen Wu err = hw->mac.acquire_swfw_sync(hw, mask);
176506abd4aSJiawen Wu if (err)
177506abd4aSJiawen Wu return err;
178506abd4aSJiawen Wu
179506abd4aSJiawen Wu err = ngbe_hic_sr_read(hw, addr, (u8 *)data, 4);
180506abd4aSJiawen Wu
181506abd4aSJiawen Wu hw->mac.release_swfw_sync(hw, mask);
182506abd4aSJiawen Wu
183506abd4aSJiawen Wu return err;
184506abd4aSJiawen Wu }
185506abd4aSJiawen Wu
186506abd4aSJiawen Wu /**
1879459ea29SJiawen Wu * ngbe_ee_write_buffer - Write EEPROM word(s) using hostif
1889459ea29SJiawen Wu * @hw: pointer to hardware structure
1899459ea29SJiawen Wu * @offset: offset of word in the EEPROM to write
1909459ea29SJiawen Wu * @words: number of words
1919459ea29SJiawen Wu * @data: word(s) write to the EEPROM
1929459ea29SJiawen Wu *
1939459ea29SJiawen Wu * Write a 16 bit word(s) to the EEPROM using the hostif.
1949459ea29SJiawen Wu **/
ngbe_ee_writew_buffer(struct ngbe_hw * hw,u32 offset,u32 words,void * data)1959459ea29SJiawen Wu s32 ngbe_ee_writew_buffer(struct ngbe_hw *hw,
1969459ea29SJiawen Wu u32 offset, u32 words, void *data)
1979459ea29SJiawen Wu {
1989459ea29SJiawen Wu const u32 mask = NGBE_MNGSEM_SWMBX | NGBE_MNGSEM_SWFLASH;
1999459ea29SJiawen Wu u32 addr = (offset << 1);
2009459ea29SJiawen Wu u32 len = (words << 1);
2019459ea29SJiawen Wu u8 *buf = (u8 *)data;
2029459ea29SJiawen Wu int err;
2039459ea29SJiawen Wu
2049459ea29SJiawen Wu err = hw->mac.acquire_swfw_sync(hw, mask);
2059459ea29SJiawen Wu if (err)
2069459ea29SJiawen Wu return err;
2079459ea29SJiawen Wu
2089459ea29SJiawen Wu while (len) {
2099459ea29SJiawen Wu u32 seg = (len <= NGBE_PMMBX_DATA_SIZE
2109459ea29SJiawen Wu ? len : NGBE_PMMBX_DATA_SIZE);
2119459ea29SJiawen Wu
2129459ea29SJiawen Wu err = ngbe_hic_sr_write(hw, addr, buf, seg);
2139459ea29SJiawen Wu if (err)
2149459ea29SJiawen Wu break;
2159459ea29SJiawen Wu
2169459ea29SJiawen Wu len -= seg;
2179459ea29SJiawen Wu buf += seg;
2189459ea29SJiawen Wu }
2199459ea29SJiawen Wu
2209459ea29SJiawen Wu hw->mac.release_swfw_sync(hw, mask);
2219459ea29SJiawen Wu return err;
2229459ea29SJiawen Wu }
2239459ea29SJiawen Wu
2249459ea29SJiawen Wu /**
225f501a195SJiawen Wu * ngbe_validate_eeprom_checksum_em - Validate EEPROM checksum
226f501a195SJiawen Wu * @hw: pointer to hardware structure
227f501a195SJiawen Wu * @checksum_val: calculated checksum
228f501a195SJiawen Wu *
229f501a195SJiawen Wu * Performs checksum calculation and validates the EEPROM checksum. If the
230f501a195SJiawen Wu * caller does not need checksum_val, the value can be NULL.
231f501a195SJiawen Wu **/
ngbe_validate_eeprom_checksum_em(struct ngbe_hw * hw,u16 * checksum_val)232f501a195SJiawen Wu s32 ngbe_validate_eeprom_checksum_em(struct ngbe_hw *hw,
233f501a195SJiawen Wu u16 *checksum_val)
234f501a195SJiawen Wu {
235f501a195SJiawen Wu u32 eeprom_cksum_devcap = 0;
236f501a195SJiawen Wu int err = 0;
237f501a195SJiawen Wu
238f501a195SJiawen Wu UNREFERENCED_PARAMETER(checksum_val);
239f501a195SJiawen Wu
240f501a195SJiawen Wu /* Check EEPROM only once */
241f501a195SJiawen Wu if (hw->bus.lan_id == 0) {
242f501a195SJiawen Wu wr32(hw, NGBE_CALSUM_CAP_STATUS, 0x0);
243f501a195SJiawen Wu wr32(hw, NGBE_EEPROM_VERSION_STORE_REG, 0x0);
244f501a195SJiawen Wu } else {
245f501a195SJiawen Wu eeprom_cksum_devcap = rd32(hw, NGBE_CALSUM_CAP_STATUS);
246f501a195SJiawen Wu hw->rom.saved_version = rd32(hw, NGBE_EEPROM_VERSION_STORE_REG);
247f501a195SJiawen Wu }
248f501a195SJiawen Wu
249f501a195SJiawen Wu if (hw->bus.lan_id == 0 || eeprom_cksum_devcap == 0) {
250f501a195SJiawen Wu err = ngbe_hic_check_cap(hw);
251f501a195SJiawen Wu if (err != 0) {
252f501a195SJiawen Wu PMD_INIT_LOG(ERR,
253f501a195SJiawen Wu "The EEPROM checksum is not valid: %d", err);
254f501a195SJiawen Wu return -EIO;
255f501a195SJiawen Wu }
256f501a195SJiawen Wu }
257f501a195SJiawen Wu
258f501a195SJiawen Wu hw->rom.cksum_devcap = eeprom_cksum_devcap & 0xffff;
259f501a195SJiawen Wu
260f501a195SJiawen Wu return err;
261f501a195SJiawen Wu }
262f501a195SJiawen Wu
263506abd4aSJiawen Wu /**
264506abd4aSJiawen Wu * ngbe_save_eeprom_version
265506abd4aSJiawen Wu * @hw: pointer to hardware structure
266506abd4aSJiawen Wu *
267506abd4aSJiawen Wu * Save off EEPROM version number and Option Rom version which
268506abd4aSJiawen Wu * together make a unique identify for the eeprom
269506abd4aSJiawen Wu */
ngbe_save_eeprom_version(struct ngbe_hw * hw)270506abd4aSJiawen Wu s32 ngbe_save_eeprom_version(struct ngbe_hw *hw)
271506abd4aSJiawen Wu {
272506abd4aSJiawen Wu u32 eeprom_verl = 0;
273506abd4aSJiawen Wu u32 etrack_id = 0;
274506abd4aSJiawen Wu u32 offset = (hw->rom.sw_addr + NGBE_EEPROM_VERSION_L) << 1;
275506abd4aSJiawen Wu
276506abd4aSJiawen Wu if (hw->bus.lan_id == 0) {
277506abd4aSJiawen Wu hw->rom.read32(hw, offset, &eeprom_verl);
278506abd4aSJiawen Wu etrack_id = eeprom_verl;
279506abd4aSJiawen Wu wr32(hw, NGBE_EEPROM_VERSION_STORE_REG, etrack_id);
280506abd4aSJiawen Wu wr32(hw, NGBE_CALSUM_CAP_STATUS,
281506abd4aSJiawen Wu hw->rom.cksum_devcap | 0x10000);
282506abd4aSJiawen Wu } else if (hw->rom.cksum_devcap) {
283506abd4aSJiawen Wu etrack_id = hw->rom.saved_version;
284506abd4aSJiawen Wu } else {
285506abd4aSJiawen Wu hw->rom.read32(hw, offset, &eeprom_verl);
286506abd4aSJiawen Wu etrack_id = eeprom_verl;
287506abd4aSJiawen Wu }
288506abd4aSJiawen Wu
289506abd4aSJiawen Wu hw->eeprom_id = etrack_id;
290506abd4aSJiawen Wu
291506abd4aSJiawen Wu return 0;
292506abd4aSJiawen Wu }
293