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