xref: /dpdk/drivers/net/ngbe/base/ngbe_eeprom.c (revision c18385220f776855a1b2eb798d44068d8fa2bd6d)
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