1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #ifndef _IXGBE_BYPASS_API_H_
35 #define _IXGBE_BYPASS_API_H_
36 
37 #ifdef RTE_LIBRTE_IXGBE_BYPASS
38 
39 #include "ixgbe_bypass_defines.h"
40 /**
41  *  ixgbe_bypass_rw_generic - Bit bang data into by_pass FW
42  *
43  *  @hw: pointer to hardware structure
44  *  @cmd: Command we send to the FW
45  *  @status: The reply from the FW
46  *
47  *  Bit-bangs the cmd to the by_pass FW status points to what is returned.
48  **/
49 #define IXGBE_BYPASS_BB_WAIT 1
50 static s32 ixgbe_bypass_rw_generic(struct ixgbe_hw *hw, u32 cmd, u32 *status)
51 {
52 	int i;
53 	u32 sck, sdi, sdo, dir_sck, dir_sdi, dir_sdo;
54 	u32 esdp;
55 
56 	if (!status)
57 		return IXGBE_ERR_PARAM;
58 
59 	*status = 0;
60 
61 	/* SDP vary by MAC type */
62 	switch (hw->mac.type) {
63 	case ixgbe_mac_82599EB:
64 		sck = IXGBE_ESDP_SDP7;
65 		sdi = IXGBE_ESDP_SDP0;
66 		sdo = IXGBE_ESDP_SDP6;
67 		dir_sck = IXGBE_ESDP_SDP7_DIR;
68 		dir_sdi = IXGBE_ESDP_SDP0_DIR;
69 		dir_sdo = IXGBE_ESDP_SDP6_DIR;
70 		break;
71 	case ixgbe_mac_X540:
72 		sck = IXGBE_ESDP_SDP2;
73 		sdi = IXGBE_ESDP_SDP0;
74 		sdo = IXGBE_ESDP_SDP1;
75 		dir_sck = IXGBE_ESDP_SDP2_DIR;
76 		dir_sdi = IXGBE_ESDP_SDP0_DIR;
77 		dir_sdo = IXGBE_ESDP_SDP1_DIR;
78 		break;
79 	case ixgbe_mac_X550:
80 	case ixgbe_mac_X550EM_x:
81 	case ixgbe_mac_X550EM_a:
82 		sck = IXGBE_ESDP_SDP2;
83 		sdi = IXGBE_ESDP_SDP0;
84 		sdo = IXGBE_ESDP_SDP1;
85 		dir_sck = IXGBE_ESDP_SDP2_DIR;
86 		dir_sdi = IXGBE_ESDP_SDP0_DIR;
87 		dir_sdo = IXGBE_ESDP_SDP1_DIR;
88 		break;
89 	default:
90 		return IXGBE_ERR_DEVICE_NOT_SUPPORTED;
91 	}
92 
93 	/* Set SDP pins direction */
94 	esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
95 	esdp |= dir_sck;	/* SCK as output */
96 	esdp |= dir_sdi;	/* SDI as output */
97 	esdp &= ~dir_sdo;	/* SDO as input */
98 	esdp |= sck;
99 	esdp |= sdi;
100 	IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
101 	IXGBE_WRITE_FLUSH(hw);
102   //  TODO:
103 	msleep(IXGBE_BYPASS_BB_WAIT);
104 
105 	/* Generate start condition */
106 	esdp &= ~sdi;
107 	IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
108 	IXGBE_WRITE_FLUSH(hw);
109 	msleep(IXGBE_BYPASS_BB_WAIT);
110 
111 	esdp &= ~sck;
112 	IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
113 	IXGBE_WRITE_FLUSH(hw);
114 	msleep(IXGBE_BYPASS_BB_WAIT);
115 
116 	/* Clock out the new control word and clock in the status */
117 	for (i = 0; i < 32; i++) {
118 		if ((cmd >> (31 - i)) & 0x01) {
119 			esdp |= sdi;
120 			IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
121 		} else {
122 			esdp &= ~sdi;
123 			IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
124 		}
125 		IXGBE_WRITE_FLUSH(hw);
126 		msleep(IXGBE_BYPASS_BB_WAIT);
127 
128 		esdp |= sck;
129 		IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
130 		IXGBE_WRITE_FLUSH(hw);
131 		msleep(IXGBE_BYPASS_BB_WAIT);
132 
133 		esdp &= ~sck;
134 		IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
135 		IXGBE_WRITE_FLUSH(hw);
136 		msleep(IXGBE_BYPASS_BB_WAIT);
137 
138 		esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
139 		if (esdp & sdo)
140 			*status = (*status << 1) | 0x01;
141 		else
142 			*status = (*status << 1) | 0x00;
143 		msleep(IXGBE_BYPASS_BB_WAIT);
144 	}
145 
146 	/* stop condition */
147 	esdp |= sck;
148 	esdp &= ~sdi;
149 	IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
150 	IXGBE_WRITE_FLUSH(hw);
151 	msleep(IXGBE_BYPASS_BB_WAIT);
152 
153 	esdp |= sdi;
154 	IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
155 	IXGBE_WRITE_FLUSH(hw);
156 
157 	/* set the page bits to match the cmd that the status it belongs to */
158 	*status = (*status & 0x3fffffff) | (cmd & 0xc0000000);
159 
160 	return 0;
161 }
162 
163 /**
164  * ixgbe_bypass_valid_rd_generic - Verify valid return from bit-bang.
165  *
166  * If we send a write we can't be sure it took until we can read back
167  * that same register.  It can be a problem as some of the feilds may
168  * for valid reasons change between the time wrote the register and
169  * we read it again to verify.  So this function check everything we
170  * can check and then assumes it worked.
171  *
172  * @u32 in_reg - The register cmd for the bit-bang read.
173  * @u32 out_reg - The register returned from a bit-bang read.
174  **/
175 static bool ixgbe_bypass_valid_rd_generic(u32 in_reg, u32 out_reg)
176 {
177 	u32 mask;
178 
179 	/* Page must match for all control pages */
180 	if ((in_reg & BYPASS_PAGE_M) != (out_reg & BYPASS_PAGE_M))
181 		return false;
182 
183 	switch (in_reg & BYPASS_PAGE_M) {
184 	case BYPASS_PAGE_CTL0:
185 		/* All the following can't change since the last write
186 		 *  - All the event actions
187 		 *  - The timeout value
188 		 */
189 		mask = BYPASS_AUX_ON_M | BYPASS_MAIN_ON_M |
190 		       BYPASS_MAIN_OFF_M | BYPASS_AUX_OFF_M |
191 		       BYPASS_WDTIMEOUT_M |
192 		       BYPASS_WDT_VALUE_M;
193 		if ((out_reg & mask) != (in_reg & mask))
194 			return false;
195 
196 		/* 0x0 is never a valid value for bypass status */
197 		if (!(out_reg & BYPASS_STATUS_OFF_M))
198 			return false;
199 		break;
200 	case BYPASS_PAGE_CTL1:
201 		/* All the following can't change since the last write
202 		 *  - time valid bit
203 		 *  - time we last sent
204 		 */
205 		mask = BYPASS_CTL1_VALID_M | BYPASS_CTL1_TIME_M;
206 		if ((out_reg & mask) != (in_reg & mask))
207 			return false;
208 		break;
209 	case BYPASS_PAGE_CTL2:
210 		/* All we can check in this page is control number
211 		 * which is already done above.
212 		 */
213 		break;
214 	}
215 
216 	/* We are as sure as we can be return true */
217 	return true;
218 }
219 
220 /**
221  *  ixgbe_bypass_set_generic - Set a bypass field in the FW CTRL Regiter.
222  *
223  *  @hw: pointer to hardware structure
224  *  @cmd: The control word we are setting.
225  *  @event: The event we are setting in the FW.  This also happens to
226  *	    be the mask for the event we are setting (handy)
227  *  @action: The action we set the event to in the FW. This is in a
228  *	     bit field that happens to be what we want to put in
229  *	     the event spot (also handy)
230  **/
231 static s32 ixgbe_bypass_set_generic(struct ixgbe_hw *hw, u32 ctrl, u32 event,
232 			     u32 action)
233 {
234 	u32 by_ctl = 0;
235 	u32 cmd, verify;
236 	u32 count = 0;
237 
238 	/* Get current values */
239 	cmd = ctrl;	/* just reading only need control number */
240 	if (ixgbe_bypass_rw_generic(hw, cmd, &by_ctl))
241 		return IXGBE_ERR_INVALID_ARGUMENT;
242 
243 	/* Set to new action */
244 	cmd = (by_ctl & ~event) | BYPASS_WE | action;
245 	if (ixgbe_bypass_rw_generic(hw, cmd, &by_ctl))
246 		return IXGBE_ERR_INVALID_ARGUMENT;
247 
248 	/* Page 0 force a FW eeprom write which is slow so verify */
249 	if ((cmd & BYPASS_PAGE_M) == BYPASS_PAGE_CTL0) {
250 		verify = BYPASS_PAGE_CTL0;
251 		do {
252 			if (count++ > 5)
253 				return IXGBE_BYPASS_FW_WRITE_FAILURE;
254 
255 			if (ixgbe_bypass_rw_generic(hw, verify, &by_ctl))
256 				return IXGBE_ERR_INVALID_ARGUMENT;
257 		} while (!ixgbe_bypass_valid_rd_generic(cmd, by_ctl));
258 	} else {
259 		/* We have give the FW time for the write to stick */
260 		msleep(100);
261 	}
262 
263 	return 0;
264 }
265 
266 /**
267  *  ixgbe_bypass_rd_eep_generic - Read the bypass FW eeprom address.
268  *
269  *  @hw: pointer to hardware structure
270  *  @addr: The bypass eeprom address to read.
271  *  @value: The 8b of data at the address above.
272  **/
273 static s32 ixgbe_bypass_rd_eep_generic(struct ixgbe_hw *hw, u32 addr, u8 *value)
274 {
275 	u32 cmd;
276 	u32 status;
277 
278 
279 	/* send the request */
280 	cmd = BYPASS_PAGE_CTL2 | BYPASS_WE;
281 	cmd |= (addr << BYPASS_CTL2_OFFSET_SHIFT) & BYPASS_CTL2_OFFSET_M;
282 	if (ixgbe_bypass_rw_generic(hw, cmd, &status))
283 		return IXGBE_ERR_INVALID_ARGUMENT;
284 
285 	/* We have give the FW time for the write to stick */
286 	msleep(100);
287 
288 	/* now read the results */
289 	cmd &= ~BYPASS_WE;
290 	if (ixgbe_bypass_rw_generic(hw, cmd, &status))
291 		return IXGBE_ERR_INVALID_ARGUMENT;
292 
293 	*value = status & BYPASS_CTL2_DATA_M;
294 
295 	return 0;
296 }
297 
298 #endif /* RTE_LIBRTE_IXGBE_BYPASS */
299 
300 #endif /* _IXGBE_BYPASS_API_H_ */
301