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/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