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
aq_fw_reset(struct aq_hw * hw)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
aq_fw_ops_init(struct aq_hw * hw)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
mac_soft_reset(struct aq_hw * hw,enum aq_fw_bootloader_mode * mode)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
mac_soft_reset_flb(struct aq_hw * hw)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
mac_soft_reset_rbl(struct aq_hw * hw,enum aq_fw_bootloader_mode * mode)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
wait_init_mac_firmware(struct aq_hw * hw)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