xref: /freebsd/sys/dev/aq/aq_fw.c (revision f9bc005b8ef3b507a5ecbc2d7fe4411ef70eff38)
1 /*
2  * aQuantia Corporation Network Driver
3  * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  *   (1) Redistributions of source code must retain the above
10  *   copyright notice, this list of conditions and the following
11  *   disclaimer.
12  *
13  *   (2) Redistributions in binary form must reproduce the above
14  *   copyright notice, this list of conditions and the following
15  *   disclaimer in the documentation and/or other materials provided
16  *   with the distribution.
17  *
18  *   (3) The name of the author may not be used to endorse or promote
19  *   products derived from this software without specific prior
20  *   written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
23  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
26  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
28  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  *
34  * @file aq_fw.c
35  * Firmware-related functions implementation.
36  * @date 2017.12.07  @author roman.agafonov@aquantia.com
37  */
38 
39 #include <sys/errno.h>
40 
41 #include "aq_common.h"
42 
43 #include "aq_hw.h"
44 #include "aq_hw_llh.h"
45 #include "aq_hw_llh_internal.h"
46 
47 #include "aq_fw.h"
48 
49 #include "aq_dbg.h"
50 
51 
52 enum aq_fw_bootloader_mode
53 {
54 	boot_mode_unknown = 0,
55 	boot_mode_flb,
56 	boot_mode_rbl_flash,
57 	boot_mode_rbl_host_bootload,
58 };
59 
60 #define AQ_CFG_HOST_BOOT_DISABLE 0
61 
62 // Timeouts
63 #define RBL_TIMEOUT_MS              10000
64 #define MAC_FW_START_TIMEOUT_MS     10000
65 #define FW_LOADER_START_TIMEOUT_MS  10000
66 
67 const uint32_t NO_RESET_SCRATCHPAD_ADDRESS = 0;
68 const uint32_t NO_RESET_SCRATCHPAD_LEN_RES = 1;
69 const uint32_t NO_RESET_SCRATCHPAD_RBL_STATUS = 2;
70 const uint32_t NO_RESET_SCRATCHPAD_RBL_STATUS_2 = 3;
71 const uint32_t WRITE_DATA_COMPLETE = 0x55555555;
72 const uint32_t WRITE_DATA_CHUNK_DONE = 0xaaaaaaaa;
73 const uint32_t WRITE_DATA_FAIL_WRONG_ADDRESS = 0x66666666;
74 
75 const uint32_t WAIT_WRITE_TIMEOUT = 1;
76 const uint32_t WAIT_WRITE_TIMEOUT_COUNT = 1000;
77 
78 const uint32_t RBL_STATUS_SUCCESS = 0xabba;
79 const uint32_t RBL_STATUS_FAILURE = 0xbad;
80 const uint32_t RBL_STATUS_HOST_BOOT = 0xf1a7;
81 
82 const uint32_t SCRATCHPAD_FW_LOADER_STATUS = (0x40 / sizeof(uint32_t));
83 
84 
85 static int mac_soft_reset(struct aq_hw* hw, enum aq_fw_bootloader_mode* mode);
86 static int mac_soft_reset_flb(struct aq_hw* hw);
87 static int mac_soft_reset_rbl(struct aq_hw* hw, enum aq_fw_bootloader_mode* mode);
88 static int wait_init_mac_firmware(struct aq_hw* hw);
89 
90 
91 int
92 aq_fw_reset(struct aq_hw* hw)
93 {
94 	int ver = AQ_READ_REG(hw, 0x18);
95 	uint32_t boot_exit_code = 0;
96 	int k;
97 
98 	for (k = 0; k < 1000; ++k) {
99 		uint32_t flb_status = reg_glb_daisy_chain_status1_get(hw);
100 		boot_exit_code = AQ_READ_REG(hw, 0x388);
101 		if (flb_status != 0x06000000 || boot_exit_code != 0)
102 			break;
103 	}
104 
105 	if (k == 1000) {
106 		device_printf(hw->dev, "Neither RBL nor FLB started\n");
107 		return (EBUSY);
108 	}
109 
110 	hw->rbl_enabled = boot_exit_code != 0;
111 
112 	trace(hw, dbg_init, "RBL enabled = %d", hw->rbl_enabled);
113 
114 	/* Having FW version 0 is an indicator that cold start
115 	 * is in progress. This means two things:
116 	 * 1) Driver have to wait for FW/HW to finish boot (500ms giveup)
117 	 * 2) Driver may skip reset sequence and save time.
118 	 */
119 	if (hw->fast_start_enabled && !ver) {
120 		int err = wait_init_mac_firmware(hw);
121 		/* Skip reset as it just completed */
122 		if (!err)
123 			return (0);
124 	}
125 
126 	enum aq_fw_bootloader_mode mode = boot_mode_unknown;
127 	int err = mac_soft_reset(hw, &mode);
128 	if (err != 0) {
129 		device_printf(hw->dev, "MAC reset failed: %d\n", err);
130 		return (err);
131 	}
132 
133 	switch (mode) {
134 	case boot_mode_flb:
135 		aq_log(hw, "FLB> F/W successfully loaded from flash.");
136 		hw->flash_present = true;
137 		return wait_init_mac_firmware(hw);
138 
139 	case boot_mode_rbl_flash:
140 		aq_log(hw, "RBL> F/W loaded from flash. Host Bootload disabled.");
141 		hw->flash_present = true;
142 		return wait_init_mac_firmware(hw);
143 
144 	case boot_mode_unknown:
145 		device_printf(hw->dev, "F/W bootload error: unknown bootloader type\n");
146 		return (ENOTSUP);
147 
148 	case boot_mode_rbl_host_bootload:
149 #if AQ_CFG_HOST_BOOT_DISABLE
150 		device_printf(hw->dev, "RBL> Host Bootload mode: this driver does not support Host Boot\n");
151 		return (ENOTSUP);
152 #else
153 		trace(hw, dbg_init, "RBL> Host Bootload mode");
154 		break;
155 #endif // HOST_BOOT_DISABLE
156 	}
157 
158 	/*
159 	 * #todo: Host Boot
160 	 */
161 	device_printf(hw->dev, "RBL> F/W Host Bootload not implemented\n");
162 
163 	return (ENOTSUP);
164 }
165 
166 int
167 aq_fw_ops_init(struct aq_hw* hw)
168 {
169 	if (hw->fw_version.raw == 0)
170 		hw->fw_version.raw = AQ_READ_REG(hw, 0x18);
171 
172 	aq_log(hw, "MAC F/W version is %d.%d.%d",
173 	    hw->fw_version.major_version, hw->fw_version.minor_version,
174 	    hw->fw_version.build_number);
175 
176 	if (hw->fw_version.major_version == 1) {
177 		trace(hw, dbg_init, "using F/W ops v1.x");
178 		hw->fw_ops = &aq_fw1x_ops;
179 		return (0);
180 	} else if (hw->fw_version.major_version >= 2) {
181 		trace(hw, dbg_init, "using F/W ops v2.x");
182 		hw->fw_ops = &aq_fw2x_ops;
183 		return (0);
184 	}
185 
186 	device_printf(hw->dev, "aq_fw_ops_init(): invalid F/W version %#x\n",
187 	    hw->fw_version.raw);
188 	return (ENOTSUP);
189 }
190 
191 
192 static int
193 mac_soft_reset(struct aq_hw* hw, enum aq_fw_bootloader_mode* mode /*= nullptr*/)
194 {
195 	if (hw->rbl_enabled) {
196 		return mac_soft_reset_rbl(hw, mode);
197 	} else {
198 		if (mode)
199 			*mode = boot_mode_flb;
200 
201 		return mac_soft_reset_flb(hw);
202 	}
203 }
204 
205 static int
206 mac_soft_reset_flb(struct aq_hw* hw)
207 {
208 	int k;
209 
210 	reg_global_ctl2_set(hw, 0x40e1);
211 	// Let Felicity hardware complete SMBUS transaction before Global
212 	// software reset.
213 	DELAY((50) * 1000);
214 
215 	/*
216 	 * If SPI burst transaction was interrupted(before running the script),
217 	 * global software reset may not clear SPI interface. Clean it up
218 	 * manually before global reset.
219 	 */
220 	reg_glb_nvr_provisioning2_set(hw, 0xa0);
221 	reg_glb_nvr_interface1_set(hw, 0x9f);
222 	reg_glb_nvr_interface1_set(hw, 0x809f);
223 	DELAY((50) * 1000);
224 
225 	reg_glb_standard_ctl1_set(hw, (reg_glb_standard_ctl1_get(hw) & ~glb_reg_res_dis_msk) | glb_soft_res_msk);
226 
227 	// Kickstart.
228 	reg_global_ctl2_set(hw, 0x80e0);
229 	reg_mif_power_gating_enable_control_set(hw, 0);
230 	if (!hw->fast_start_enabled)
231 		reg_glb_general_provisioning9_set(hw, 1);
232 
233 	/*
234 	 * For the case SPI burst transaction was interrupted (by MCP reset
235 	 * above), wait until it is completed by hardware.
236 	 */
237 	DELAY(50 * 1000);
238 
239 	/* MAC Kickstart */
240 	if (!hw->fast_start_enabled) {
241 		reg_global_ctl2_set(hw, 0x180e0);
242 
243 		uint32_t flb_status = 0;
244 		int k;
245 		for (k = 0; k < 1000; ++k) {
246 			flb_status = reg_glb_daisy_chain_status1_get(hw) & 0x10;
247 			if (flb_status != 0)
248 				break;
249 			DELAY(10 * 1000);
250 		}
251 
252 		if (flb_status == 0) {
253 			trace_error(hw, dbg_init,
254 			    "FLB> MAC kickstart failed: timed out");
255 			return (ETIMEDOUT);
256 		}
257 
258 		trace(hw, dbg_init, "FLB> MAC kickstart done, %d ms", k);
259 		/* FW reset */
260 		reg_global_ctl2_set(hw, 0x80e0);
261 		// Let Felicity hardware complete SMBUS transaction before
262 		// Global software reset.
263 		DELAY((50) * 1000);
264 	}
265 	reg_glb_cpu_sem_set(hw, 1, 0);
266 
267 	// PHY Kickstart: #undone
268 
269 	// Global software reset
270 	rx_rx_reg_res_dis_set(hw, 0);
271 	tx_tx_reg_res_dis_set(hw, 0);
272 	mpi_tx_reg_res_dis_set(hw, 0);
273 	reg_glb_standard_ctl1_set(hw, (reg_glb_standard_ctl1_get(hw) & ~glb_reg_res_dis_msk) | glb_soft_res_msk);
274 
275 	bool restart_completed = false;
276 	for (k = 0; k < 1000; ++k) {
277 		restart_completed = reg_glb_fw_image_id1_get(hw) != 0;
278 		if (restart_completed)
279 			break;
280 		DELAY((10) * 1000);
281 	}
282 
283 	if (!restart_completed) {
284 		trace_error(hw, dbg_init, "FLB> Global Soft Reset failed");
285 		return (ETIMEDOUT);
286 	}
287 
288 	trace(hw, dbg_init, "FLB> F/W restart: %d ms", k * 10);
289 	return (0);
290 }
291 
292 static int
293 mac_soft_reset_rbl(struct aq_hw* hw, enum aq_fw_bootloader_mode* mode)
294 {
295 	trace(hw, dbg_init, "RBL> MAC reset STARTED!");
296 
297 	reg_global_ctl2_set(hw, 0x40e1);
298 	reg_glb_cpu_sem_set(hw, 1, 0);
299 	reg_mif_power_gating_enable_control_set(hw, 0);
300 
301 	// MAC FW will reload PHY FW if 1E.1000.3 was cleaned - #undone
302 
303 	reg_glb_cpu_no_reset_scratchpad_set(hw, 0xDEAD,
304 	    NO_RESET_SCRATCHPAD_RBL_STATUS);
305 
306 	/* Clear a stale flash burst so the global reset frees the SPI bus. */
307 	uint32_t spi = AQ_READ_REG(hw, 0x53c);
308 	AQ_WRITE_REG(hw, 0x53c, spi | 0x10);
309 
310 	// Global software reset
311 	rx_rx_reg_res_dis_set(hw, 0);
312 	tx_tx_reg_res_dis_set(hw, 0);
313 	mpi_tx_reg_res_dis_set(hw, 0);
314 	reg_glb_standard_ctl1_set(hw, (reg_glb_standard_ctl1_get(hw) & ~glb_reg_res_dis_msk) | glb_soft_res_msk);
315 
316 	reg_global_ctl2_set(hw, 0x40e0);
317 
318 	// Wait for RBL to finish boot process.
319 	uint16_t rbl_status = 0;
320 	for (int k = 0; k < RBL_TIMEOUT_MS; ++k) {
321 		rbl_status = ((uint16_t)(reg_glb_cpu_no_reset_scratchpad_get(hw, NO_RESET_SCRATCHPAD_RBL_STATUS)));
322 		if (rbl_status != 0 && rbl_status != 0xDEAD)
323 			break;
324 
325 		DELAY((1) * 1000);
326 	}
327 
328 	if (rbl_status == 0 || rbl_status == 0xDEAD) {
329 		trace_error(hw, dbg_init, "RBL> RBL restart failed: timeout");
330 		return (EBUSY);
331 	}
332 
333 	if (rbl_status == RBL_STATUS_SUCCESS) {
334 		if (mode)
335 			*mode = boot_mode_rbl_flash;
336 		trace(hw, dbg_init, "RBL> reset complete! [Flash]");
337 	} else if (rbl_status == RBL_STATUS_HOST_BOOT) {
338 		if (mode)
339 			*mode = boot_mode_rbl_host_bootload;
340 		trace(hw, dbg_init, "RBL> reset complete! [Host Bootload]");
341 	} else {
342 		trace_error(hw, dbg_init, "unknown RBL status 0x%x", rbl_status);
343 		return (EBUSY);
344 	}
345 
346 	return (0);
347 }
348 
349 static int
350 wait_init_mac_firmware(struct aq_hw* hw)
351 {
352 	for (int i = 0; i < MAC_FW_START_TIMEOUT_MS; ++i) {
353 		if ((hw->fw_version.raw = AQ_READ_REG(hw, 0x18)) != 0)
354 			return (0);
355 
356 		DELAY((1) * 1000);
357 	}
358 
359 	trace_error(hw, dbg_init,
360 	    "timeout waiting for reg 0x18. MAC f/w NOT READY");
361 	return (EBUSY);
362 }
363