Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/dev/aq/aq_fw.c
96295 views
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 [email protected]
37
*/
38
39
#include <sys/cdefs.h>
40
__FBSDID("$FreeBSD$");
41
42
#include <sys/errno.h>
43
44
#include "aq_common.h"
45
46
#include "aq_hw.h"
47
#include "aq_hw_llh.h"
48
#include "aq_hw_llh_internal.h"
49
50
#include "aq_fw.h"
51
#include "aq_common.h"
52
53
#include "aq_dbg.h"
54
55
56
typedef enum aq_fw_bootloader_mode
57
{
58
boot_mode_unknown = 0,
59
boot_mode_flb,
60
boot_mode_rbl_flash,
61
boot_mode_rbl_host_bootload,
62
} aq_fw_bootloader_mode;
63
64
#define AQ_CFG_HOST_BOOT_DISABLE 0
65
66
// Timeouts
67
#define RBL_TIMEOUT_MS 10000
68
#define MAC_FW_START_TIMEOUT_MS 10000
69
#define FW_LOADER_START_TIMEOUT_MS 10000
70
71
const uint32_t NO_RESET_SCRATCHPAD_ADDRESS = 0;
72
const uint32_t NO_RESET_SCRATCHPAD_LEN_RES = 1;
73
const uint32_t NO_RESET_SCRATCHPAD_RBL_STATUS = 2;
74
const uint32_t NO_RESET_SCRATCHPAD_RBL_STATUS_2 = 3;
75
const uint32_t WRITE_DATA_COMPLETE = 0x55555555;
76
const uint32_t WRITE_DATA_CHUNK_DONE = 0xaaaaaaaa;
77
const uint32_t WRITE_DATA_FAIL_WRONG_ADDRESS = 0x66666666;
78
79
const uint32_t WAIT_WRITE_TIMEOUT = 1;
80
const uint32_t WAIT_WRITE_TIMEOUT_COUNT = 1000;
81
82
const uint32_t RBL_STATUS_SUCCESS = 0xabba;
83
const uint32_t RBL_STATUS_FAILURE = 0xbad;
84
const uint32_t RBL_STATUS_HOST_BOOT = 0xf1a7;
85
86
const uint32_t SCRATCHPAD_FW_LOADER_STATUS = (0x40 / sizeof(uint32_t));
87
88
89
extern struct aq_firmware_ops aq_fw1x_ops;
90
extern struct aq_firmware_ops aq_fw2x_ops;
91
92
93
int mac_soft_reset_(struct aq_hw* hw, aq_fw_bootloader_mode* mode);
94
int mac_soft_reset_flb_(struct aq_hw* hw);
95
int mac_soft_reset_rbl_(struct aq_hw* hw, aq_fw_bootloader_mode* mode);
96
int wait_init_mac_firmware_(struct aq_hw* hw);
97
98
99
int
100
aq_fw_reset(struct aq_hw* hw)
101
{
102
int ver = AQ_READ_REG(hw, 0x18);
103
uint32_t bootExitCode = 0;
104
int k;
105
106
for (k = 0; k < 1000; ++k) {
107
uint32_t flbStatus = reg_glb_daisy_chain_status1_get(hw);
108
bootExitCode = AQ_READ_REG(hw, 0x388);
109
if (flbStatus != 0x06000000 || bootExitCode != 0)
110
break;
111
}
112
113
if (k == 1000) {
114
aq_log_error("Neither RBL nor FLB started");
115
return (-EBUSY);
116
}
117
118
hw->rbl_enabled = bootExitCode != 0;
119
120
trace(dbg_init, "RBL enabled = %d", hw->rbl_enabled);
121
122
/* Having FW version 0 is an indicator that cold start
123
* is in progress. This means two things:
124
* 1) Driver have to wait for FW/HW to finish boot (500ms giveup)
125
* 2) Driver may skip reset sequence and save time.
126
*/
127
if (hw->fast_start_enabled && !ver) {
128
int err = wait_init_mac_firmware_(hw);
129
/* Skip reset as it just completed */
130
if (!err)
131
return (0);
132
}
133
134
aq_fw_bootloader_mode mode = boot_mode_unknown;
135
int err = mac_soft_reset_(hw, &mode);
136
if (err < 0) {
137
aq_log_error("MAC reset failed: %d", err);
138
return (err);
139
}
140
141
switch (mode) {
142
case boot_mode_flb:
143
aq_log("FLB> F/W successfully loaded from flash.");
144
hw->flash_present = true;
145
return wait_init_mac_firmware_(hw);
146
147
case boot_mode_rbl_flash:
148
aq_log("RBL> F/W loaded from flash. Host Bootload disabled.");
149
hw->flash_present = true;
150
return wait_init_mac_firmware_(hw);
151
152
case boot_mode_unknown:
153
aq_log_error("F/W bootload error: unknown bootloader type");
154
return (-ENOTSUP);
155
156
case boot_mode_rbl_host_bootload:
157
#if AQ_CFG_HOST_BOOT_DISABLE
158
aq_log_error("RBL> Host Bootload mode: this driver does not support Host Boot");
159
return (-ENOTSUP);
160
#else
161
trace(dbg_init, "RBL> Host Bootload mode");
162
break;
163
#endif // HOST_BOOT_DISABLE
164
}
165
166
/*
167
* #todo: Host Boot
168
*/
169
aq_log_error("RBL> F/W Host Bootload not implemented");
170
171
return (-ENOTSUP);
172
}
173
174
int
175
aq_fw_ops_init(struct aq_hw* hw)
176
{
177
if (hw->fw_version.raw == 0)
178
hw->fw_version.raw = AQ_READ_REG(hw, 0x18);
179
180
aq_log("MAC F/W version is %d.%d.%d",
181
hw->fw_version.major_version, hw->fw_version.minor_version,
182
hw->fw_version.build_number);
183
184
if (hw->fw_version.major_version == 1) {
185
trace(dbg_init, "using F/W ops v1.x");
186
hw->fw_ops = &aq_fw1x_ops;
187
return (EOK);
188
} else if (hw->fw_version.major_version >= 2) {
189
trace(dbg_init, "using F/W ops v2.x");
190
hw->fw_ops = &aq_fw2x_ops;
191
return (EOK);
192
}
193
194
aq_log_error("aq_fw_ops_init(): invalid F/W version %#x",
195
hw->fw_version.raw);
196
return (-ENOTSUP);
197
}
198
199
200
int
201
mac_soft_reset_(struct aq_hw* hw, aq_fw_bootloader_mode* mode /*= nullptr*/)
202
{
203
if (hw->rbl_enabled) {
204
return mac_soft_reset_rbl_(hw, mode);
205
} else {
206
if (mode)
207
*mode = boot_mode_flb;
208
209
return mac_soft_reset_flb_(hw);
210
}
211
}
212
213
int
214
mac_soft_reset_flb_(struct aq_hw* hw)
215
{
216
int k;
217
218
reg_global_ctl2_set(hw, 0x40e1);
219
// Let Felicity hardware complete SMBUS transaction before Global
220
// software reset.
221
msec_delay(50);
222
223
/*
224
* If SPI burst transaction was interrupted(before running the script),
225
* global software reset may not clear SPI interface. Clean it up
226
* manually before global reset.
227
*/
228
reg_glb_nvr_provisioning2_set(hw, 0xa0);
229
reg_glb_nvr_interface1_set(hw, 0x9f);
230
reg_glb_nvr_interface1_set(hw, 0x809f);
231
msec_delay(50);
232
233
reg_glb_standard_ctl1_set(hw, (reg_glb_standard_ctl1_get(hw) & ~glb_reg_res_dis_msk) | glb_soft_res_msk);
234
235
// Kickstart.
236
reg_global_ctl2_set(hw, 0x80e0);
237
reg_mif_power_gating_enable_control_set(hw, 0);
238
if (!hw->fast_start_enabled)
239
reg_glb_general_provisioning9_set(hw, 1);
240
241
/*
242
* For the case SPI burst transaction was interrupted (by MCP reset
243
* above), wait until it is completed by hardware.
244
*/
245
msec_delay(50); // Sleep for 10 ms.
246
247
/* MAC Kickstart */
248
if (!hw->fast_start_enabled) {
249
reg_global_ctl2_set(hw, 0x180e0);
250
251
uint32_t flb_status = 0;
252
int k;
253
for (k = 0; k < 1000; ++k) {
254
flb_status = reg_glb_daisy_chain_status1_get(hw) & 0x10;
255
if (flb_status != 0)
256
break;
257
msec_delay(10); // Sleep for 10 ms.
258
}
259
260
if (flb_status == 0) {
261
trace_error(dbg_init,
262
"FLB> MAC kickstart failed: timed out");
263
return (false);
264
}
265
266
trace(dbg_init, "FLB> MAC kickstart done, %d ms", k);
267
/* FW reset */
268
reg_global_ctl2_set(hw, 0x80e0);
269
// Let Felicity hardware complete SMBUS transaction before
270
// Global software reset.
271
msec_delay(50);
272
}
273
reg_glb_cpu_sem_set(hw, 1, 0);
274
275
// PHY Kickstart: #undone
276
277
// Global software reset
278
rx_rx_reg_res_dis_set(hw, 0);
279
tx_tx_reg_res_dis_set(hw, 0);
280
mpi_tx_reg_res_dis_set(hw, 0);
281
reg_glb_standard_ctl1_set(hw, (reg_glb_standard_ctl1_get(hw) & ~glb_reg_res_dis_msk) | glb_soft_res_msk);
282
283
bool restart_completed = false;
284
for (k = 0; k < 1000; ++k) {
285
restart_completed = reg_glb_fw_image_id1_get(hw) != 0;
286
if (restart_completed)
287
break;
288
msec_delay(10);
289
}
290
291
if (!restart_completed) {
292
trace_error(dbg_init, "FLB> Global Soft Reset failed");
293
return (false);
294
}
295
296
trace(dbg_init, "FLB> F/W restart: %d ms", k * 10);
297
return (true);
298
}
299
300
int
301
mac_soft_reset_rbl_(struct aq_hw* hw, aq_fw_bootloader_mode* mode)
302
{
303
trace(dbg_init, "RBL> MAC reset STARTED!");
304
305
reg_global_ctl2_set(hw, 0x40e1);
306
reg_glb_cpu_sem_set(hw, 1, 0);
307
reg_mif_power_gating_enable_control_set(hw, 0);
308
309
// MAC FW will reload PHY FW if 1E.1000.3 was cleaned - #undone
310
311
reg_glb_cpu_no_reset_scratchpad_set(hw, 0xDEAD,
312
NO_RESET_SCRATCHPAD_RBL_STATUS);
313
314
// Global software reset
315
rx_rx_reg_res_dis_set(hw, 0);
316
tx_tx_reg_res_dis_set(hw, 0);
317
mpi_tx_reg_res_dis_set(hw, 0);
318
reg_glb_standard_ctl1_set(hw, (reg_glb_standard_ctl1_get(hw) & ~glb_reg_res_dis_msk) | glb_soft_res_msk);
319
320
reg_global_ctl2_set(hw, 0x40e0);
321
322
// Wait for RBL to finish boot process.
323
uint16_t rbl_status = 0;
324
for (int k = 0; k < RBL_TIMEOUT_MS; ++k) {
325
rbl_status = LOWORD(reg_glb_cpu_no_reset_scratchpad_get(hw, NO_RESET_SCRATCHPAD_RBL_STATUS));
326
if (rbl_status != 0 && rbl_status != 0xDEAD)
327
break;
328
329
msec_delay(1);
330
}
331
332
if (rbl_status == 0 || rbl_status == 0xDEAD) {
333
trace_error(dbg_init, "RBL> RBL restart failed: timeout");
334
return (-EBUSY);
335
}
336
337
if (rbl_status == RBL_STATUS_SUCCESS) {
338
if (mode)
339
*mode = boot_mode_rbl_flash;
340
trace(dbg_init, "RBL> reset complete! [Flash]");
341
} else if (rbl_status == RBL_STATUS_HOST_BOOT) {
342
if (mode)
343
*mode = boot_mode_rbl_host_bootload;
344
trace(dbg_init, "RBL> reset complete! [Host Bootload]");
345
} else {
346
trace_error(dbg_init, "unknown RBL status 0x%x", rbl_status);
347
return (-EBUSY);
348
}
349
350
return (EOK);
351
}
352
353
int
354
wait_init_mac_firmware_(struct aq_hw* hw)
355
{
356
for (int i = 0; i < MAC_FW_START_TIMEOUT_MS; ++i) {
357
if ((hw->fw_version.raw = AQ_READ_REG(hw, 0x18)) != 0)
358
return (EOK);
359
360
msec_delay(1);
361
}
362
363
trace_error(dbg_init,
364
"timeout waiting for reg 0x18. MAC f/w NOT READY");
365
return (-EBUSY);
366
}
367
368