1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2014 Intel Corporation
3  */
4 
5 #ifndef _IXGBE_BYPASS_API_H_
6 #define _IXGBE_BYPASS_API_H_
7 
8 #ifdef RTE_LIBRTE_IXGBE_BYPASS
9 
10 #include "ixgbe_bypass_defines.h"
11 /**
12  *  ixgbe_bypass_rw_generic - Bit bang data into by_pass FW
13  *
14  *  @hw: pointer to hardware structure
15  *  @cmd: Command we send to the FW
16  *  @status: The reply from the FW
17  *
18  *  Bit-bangs the cmd to the by_pass FW status points to what is returned.
19  **/
20 #define IXGBE_BYPASS_BB_WAIT 1
ixgbe_bypass_rw_generic(struct ixgbe_hw * hw,u32 cmd,u32 * status)21 static s32 ixgbe_bypass_rw_generic(struct ixgbe_hw *hw, u32 cmd, u32 *status)
22 {
23 	int i;
24 	u32 sck, sdi, sdo, dir_sck, dir_sdi, dir_sdo;
25 	u32 esdp;
26 
27 	if (!status)
28 		return IXGBE_ERR_PARAM;
29 
30 	*status = 0;
31 
32 	/* SDP vary by MAC type */
33 	switch (hw->mac.type) {
34 	case ixgbe_mac_82599EB:
35 		sck = IXGBE_ESDP_SDP7;
36 		sdi = IXGBE_ESDP_SDP0;
37 		sdo = IXGBE_ESDP_SDP6;
38 		dir_sck = IXGBE_ESDP_SDP7_DIR;
39 		dir_sdi = IXGBE_ESDP_SDP0_DIR;
40 		dir_sdo = IXGBE_ESDP_SDP6_DIR;
41 		break;
42 	case ixgbe_mac_X540:
43 		sck = IXGBE_ESDP_SDP2;
44 		sdi = IXGBE_ESDP_SDP0;
45 		sdo = IXGBE_ESDP_SDP1;
46 		dir_sck = IXGBE_ESDP_SDP2_DIR;
47 		dir_sdi = IXGBE_ESDP_SDP0_DIR;
48 		dir_sdo = IXGBE_ESDP_SDP1_DIR;
49 		break;
50 	case ixgbe_mac_X550:
51 	case ixgbe_mac_X550EM_x:
52 	case ixgbe_mac_X550EM_a:
53 		sck = IXGBE_ESDP_SDP2;
54 		sdi = IXGBE_ESDP_SDP0;
55 		sdo = IXGBE_ESDP_SDP1;
56 		dir_sck = IXGBE_ESDP_SDP2_DIR;
57 		dir_sdi = IXGBE_ESDP_SDP0_DIR;
58 		dir_sdo = IXGBE_ESDP_SDP1_DIR;
59 		break;
60 	default:
61 		return IXGBE_ERR_DEVICE_NOT_SUPPORTED;
62 	}
63 
64 	/* Set SDP pins direction */
65 	esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
66 	esdp |= dir_sck;	/* SCK as output */
67 	esdp |= dir_sdi;	/* SDI as output */
68 	esdp &= ~dir_sdo;	/* SDO as input */
69 	esdp |= sck;
70 	esdp |= sdi;
71 	IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
72 	IXGBE_WRITE_FLUSH(hw);
73   //  TODO:
74 	msleep(IXGBE_BYPASS_BB_WAIT);
75 
76 	/* Generate start condition */
77 	esdp &= ~sdi;
78 	IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
79 	IXGBE_WRITE_FLUSH(hw);
80 	msleep(IXGBE_BYPASS_BB_WAIT);
81 
82 	esdp &= ~sck;
83 	IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
84 	IXGBE_WRITE_FLUSH(hw);
85 	msleep(IXGBE_BYPASS_BB_WAIT);
86 
87 	/* Clock out the new control word and clock in the status */
88 	for (i = 0; i < 32; i++) {
89 		if ((cmd >> (31 - i)) & 0x01) {
90 			esdp |= sdi;
91 			IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
92 		} else {
93 			esdp &= ~sdi;
94 			IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
95 		}
96 		IXGBE_WRITE_FLUSH(hw);
97 		msleep(IXGBE_BYPASS_BB_WAIT);
98 
99 		esdp |= sck;
100 		IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
101 		IXGBE_WRITE_FLUSH(hw);
102 		msleep(IXGBE_BYPASS_BB_WAIT);
103 
104 		esdp &= ~sck;
105 		IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
106 		IXGBE_WRITE_FLUSH(hw);
107 		msleep(IXGBE_BYPASS_BB_WAIT);
108 
109 		esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
110 		if (esdp & sdo)
111 			*status = (*status << 1) | 0x01;
112 		else
113 			*status = (*status << 1) | 0x00;
114 		msleep(IXGBE_BYPASS_BB_WAIT);
115 	}
116 
117 	/* stop condition */
118 	esdp |= sck;
119 	esdp &= ~sdi;
120 	IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
121 	IXGBE_WRITE_FLUSH(hw);
122 	msleep(IXGBE_BYPASS_BB_WAIT);
123 
124 	esdp |= sdi;
125 	IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
126 	IXGBE_WRITE_FLUSH(hw);
127 
128 	/* set the page bits to match the cmd that the status it belongs to */
129 	*status = (*status & 0x3fffffff) | (cmd & 0xc0000000);
130 
131 	return 0;
132 }
133 
134 /**
135  * ixgbe_bypass_valid_rd_generic - Verify valid return from bit-bang.
136  *
137  * If we send a write we can't be sure it took until we can read back
138  * that same register.  It can be a problem as some of the feilds may
139  * for valid reasons change between the time wrote the register and
140  * we read it again to verify.  So this function check everything we
141  * can check and then assumes it worked.
142  *
143  * @u32 in_reg - The register cmd for the bit-bang read.
144  * @u32 out_reg - The register returned from a bit-bang read.
145  **/
ixgbe_bypass_valid_rd_generic(u32 in_reg,u32 out_reg)146 static bool ixgbe_bypass_valid_rd_generic(u32 in_reg, u32 out_reg)
147 {
148 	u32 mask;
149 
150 	/* Page must match for all control pages */
151 	if ((in_reg & BYPASS_PAGE_M) != (out_reg & BYPASS_PAGE_M))
152 		return false;
153 
154 	switch (in_reg & BYPASS_PAGE_M) {
155 	case BYPASS_PAGE_CTL0:
156 		/* All the following can't change since the last write
157 		 *  - All the event actions
158 		 *  - The timeout value
159 		 */
160 		mask = BYPASS_AUX_ON_M | BYPASS_MAIN_ON_M |
161 		       BYPASS_MAIN_OFF_M | BYPASS_AUX_OFF_M |
162 		       BYPASS_WDTIMEOUT_M |
163 		       BYPASS_WDT_VALUE_M;
164 		if ((out_reg & mask) != (in_reg & mask))
165 			return false;
166 
167 		/* 0x0 is never a valid value for bypass status */
168 		if (!(out_reg & BYPASS_STATUS_OFF_M))
169 			return false;
170 		break;
171 	case BYPASS_PAGE_CTL1:
172 		/* All the following can't change since the last write
173 		 *  - time valid bit
174 		 *  - time we last sent
175 		 */
176 		mask = BYPASS_CTL1_VALID_M | BYPASS_CTL1_TIME_M;
177 		if ((out_reg & mask) != (in_reg & mask))
178 			return false;
179 		break;
180 	case BYPASS_PAGE_CTL2:
181 		/* All we can check in this page is control number
182 		 * which is already done above.
183 		 */
184 		break;
185 	}
186 
187 	/* We are as sure as we can be return true */
188 	return true;
189 }
190 
191 /**
192  *  ixgbe_bypass_set_generic - Set a bypass field in the FW CTRL Regiter.
193  *
194  *  @hw: pointer to hardware structure
195  *  @cmd: The control word we are setting.
196  *  @event: The event we are setting in the FW.  This also happens to
197  *	    be the mask for the event we are setting (handy)
198  *  @action: The action we set the event to in the FW. This is in a
199  *	     bit field that happens to be what we want to put in
200  *	     the event spot (also handy)
201  **/
ixgbe_bypass_set_generic(struct ixgbe_hw * hw,u32 ctrl,u32 event,u32 action)202 static s32 ixgbe_bypass_set_generic(struct ixgbe_hw *hw, u32 ctrl, u32 event,
203 			     u32 action)
204 {
205 	u32 by_ctl = 0;
206 	u32 cmd, verify;
207 	u32 count = 0;
208 
209 	/* Get current values */
210 	cmd = ctrl;	/* just reading only need control number */
211 	if (ixgbe_bypass_rw_generic(hw, cmd, &by_ctl))
212 		return IXGBE_ERR_INVALID_ARGUMENT;
213 
214 	/* Set to new action */
215 	cmd = (by_ctl & ~event) | BYPASS_WE | action;
216 	if (ixgbe_bypass_rw_generic(hw, cmd, &by_ctl))
217 		return IXGBE_ERR_INVALID_ARGUMENT;
218 
219 	/* Page 0 force a FW eeprom write which is slow so verify */
220 	if ((cmd & BYPASS_PAGE_M) == BYPASS_PAGE_CTL0) {
221 		verify = BYPASS_PAGE_CTL0;
222 		do {
223 			if (count++ > 5)
224 				return IXGBE_BYPASS_FW_WRITE_FAILURE;
225 
226 			if (ixgbe_bypass_rw_generic(hw, verify, &by_ctl))
227 				return IXGBE_ERR_INVALID_ARGUMENT;
228 		} while (!ixgbe_bypass_valid_rd_generic(cmd, by_ctl));
229 	} else {
230 		/* We have give the FW time for the write to stick */
231 		msleep(100);
232 	}
233 
234 	return 0;
235 }
236 
237 /**
238  *  ixgbe_bypass_rd_eep_generic - Read the bypass FW eeprom address.
239  *
240  *  @hw: pointer to hardware structure
241  *  @addr: The bypass eeprom address to read.
242  *  @value: The 8b of data at the address above.
243  **/
ixgbe_bypass_rd_eep_generic(struct ixgbe_hw * hw,u32 addr,u8 * value)244 static s32 ixgbe_bypass_rd_eep_generic(struct ixgbe_hw *hw, u32 addr, u8 *value)
245 {
246 	u32 cmd;
247 	u32 status;
248 
249 
250 	/* send the request */
251 	cmd = BYPASS_PAGE_CTL2 | BYPASS_WE;
252 	cmd |= (addr << BYPASS_CTL2_OFFSET_SHIFT) & BYPASS_CTL2_OFFSET_M;
253 	if (ixgbe_bypass_rw_generic(hw, cmd, &status))
254 		return IXGBE_ERR_INVALID_ARGUMENT;
255 
256 	/* We have give the FW time for the write to stick */
257 	msleep(100);
258 
259 	/* now read the results */
260 	cmd &= ~BYPASS_WE;
261 	if (ixgbe_bypass_rw_generic(hw, cmd, &status))
262 		return IXGBE_ERR_INVALID_ARGUMENT;
263 
264 	*value = status & BYPASS_CTL2_DATA_M;
265 
266 	return 0;
267 }
268 
269 #endif /* RTE_LIBRTE_IXGBE_BYPASS */
270 
271 #endif /* _IXGBE_BYPASS_API_H_ */
272