1c1be0bf0SDmitry Bogdanov // SPDX-License-Identifier: GPL-2.0-only 2c1be0bf0SDmitry Bogdanov /* Atlantic Network Driver 3c1be0bf0SDmitry Bogdanov * Copyright (C) 2020 Marvell International Ltd. 4c1be0bf0SDmitry Bogdanov */ 5c1be0bf0SDmitry Bogdanov 6c1be0bf0SDmitry Bogdanov #include <linux/iopoll.h> 7c1be0bf0SDmitry Bogdanov 8c1be0bf0SDmitry Bogdanov #include "aq_hw_utils.h" 9c1be0bf0SDmitry Bogdanov #include "hw_atl/hw_atl_utils.h" 10c1be0bf0SDmitry Bogdanov #include "hw_atl2_utils.h" 11c1be0bf0SDmitry Bogdanov #include "hw_atl2_llh.h" 12c1be0bf0SDmitry Bogdanov #include "hw_atl2_llh_internal.h" 13c1be0bf0SDmitry Bogdanov 14c1be0bf0SDmitry Bogdanov #define HW_ATL2_FW_VER_1X 0x01000000U 15c1be0bf0SDmitry Bogdanov 16c1be0bf0SDmitry Bogdanov #define AQ_A2_BOOT_STARTED BIT(0x18) 17c1be0bf0SDmitry Bogdanov #define AQ_A2_CRASH_INIT BIT(0x1B) 18c1be0bf0SDmitry Bogdanov #define AQ_A2_BOOT_CODE_FAILED BIT(0x1C) 19c1be0bf0SDmitry Bogdanov #define AQ_A2_FW_INIT_FAILED BIT(0x1D) 20c1be0bf0SDmitry Bogdanov #define AQ_A2_FW_INIT_COMP_SUCCESS BIT(0x1F) 21c1be0bf0SDmitry Bogdanov 22c1be0bf0SDmitry Bogdanov #define AQ_A2_FW_BOOT_FAILED_MASK (AQ_A2_CRASH_INIT | \ 23c1be0bf0SDmitry Bogdanov AQ_A2_BOOT_CODE_FAILED | \ 24c1be0bf0SDmitry Bogdanov AQ_A2_FW_INIT_FAILED) 25c1be0bf0SDmitry Bogdanov #define AQ_A2_FW_BOOT_COMPLETE_MASK (AQ_A2_FW_BOOT_FAILED_MASK | \ 26c1be0bf0SDmitry Bogdanov AQ_A2_FW_INIT_COMP_SUCCESS) 27c1be0bf0SDmitry Bogdanov 28c1be0bf0SDmitry Bogdanov #define AQ_A2_FW_BOOT_REQ_REBOOT BIT(0x0) 29c1be0bf0SDmitry Bogdanov #define AQ_A2_FW_BOOT_REQ_HOST_BOOT BIT(0x8) 30c1be0bf0SDmitry Bogdanov #define AQ_A2_FW_BOOT_REQ_MAC_FAST_BOOT BIT(0xA) 31c1be0bf0SDmitry Bogdanov #define AQ_A2_FW_BOOT_REQ_PHY_FAST_BOOT BIT(0xB) 32c1be0bf0SDmitry Bogdanov 33c1be0bf0SDmitry Bogdanov int hw_atl2_utils_initfw(struct aq_hw_s *self, const struct aq_fw_ops **fw_ops) 34c1be0bf0SDmitry Bogdanov { 35c1be0bf0SDmitry Bogdanov int err; 36c1be0bf0SDmitry Bogdanov 37c1be0bf0SDmitry Bogdanov self->fw_ver_actual = hw_atl2_utils_get_fw_version(self); 38c1be0bf0SDmitry Bogdanov 39c1be0bf0SDmitry Bogdanov if (hw_atl_utils_ver_match(HW_ATL2_FW_VER_1X, 40c1be0bf0SDmitry Bogdanov self->fw_ver_actual) == 0) { 41c1be0bf0SDmitry Bogdanov *fw_ops = &aq_a2_fw_ops; 42c1be0bf0SDmitry Bogdanov } else { 43c1be0bf0SDmitry Bogdanov aq_pr_err("Bad FW version detected: %x, but continue\n", 44c1be0bf0SDmitry Bogdanov self->fw_ver_actual); 45c1be0bf0SDmitry Bogdanov *fw_ops = &aq_a2_fw_ops; 46c1be0bf0SDmitry Bogdanov } 47c1be0bf0SDmitry Bogdanov aq_pr_trace("Detect ATL2FW %x\n", self->fw_ver_actual); 48c1be0bf0SDmitry Bogdanov self->aq_fw_ops = *fw_ops; 49c1be0bf0SDmitry Bogdanov err = self->aq_fw_ops->init(self); 50c1be0bf0SDmitry Bogdanov 51c1be0bf0SDmitry Bogdanov self->chip_features |= ATL_HW_CHIP_ANTIGUA; 52c1be0bf0SDmitry Bogdanov 53c1be0bf0SDmitry Bogdanov return err; 54c1be0bf0SDmitry Bogdanov } 55c1be0bf0SDmitry Bogdanov 56c1be0bf0SDmitry Bogdanov static bool hw_atl2_mcp_boot_complete(struct aq_hw_s *self) 57c1be0bf0SDmitry Bogdanov { 58c1be0bf0SDmitry Bogdanov u32 rbl_status; 59c1be0bf0SDmitry Bogdanov 60c1be0bf0SDmitry Bogdanov rbl_status = hw_atl2_mif_mcp_boot_reg_get(self); 61c1be0bf0SDmitry Bogdanov if (rbl_status & AQ_A2_FW_BOOT_COMPLETE_MASK) 62c1be0bf0SDmitry Bogdanov return true; 63c1be0bf0SDmitry Bogdanov 64c1be0bf0SDmitry Bogdanov /* Host boot requested */ 65c1be0bf0SDmitry Bogdanov if (hw_atl2_mif_host_req_int_get(self) & HW_ATL2_MCP_HOST_REQ_INT_READY) 66c1be0bf0SDmitry Bogdanov return true; 67c1be0bf0SDmitry Bogdanov 68c1be0bf0SDmitry Bogdanov return false; 69c1be0bf0SDmitry Bogdanov } 70c1be0bf0SDmitry Bogdanov 71c1be0bf0SDmitry Bogdanov int hw_atl2_utils_soft_reset(struct aq_hw_s *self) 72c1be0bf0SDmitry Bogdanov { 73c1be0bf0SDmitry Bogdanov bool rbl_complete = false; 74c1be0bf0SDmitry Bogdanov u32 rbl_status = 0; 75c1be0bf0SDmitry Bogdanov u32 rbl_request; 76c1be0bf0SDmitry Bogdanov int err; 77c1be0bf0SDmitry Bogdanov 78c1be0bf0SDmitry Bogdanov err = readx_poll_timeout_atomic(hw_atl2_mif_mcp_boot_reg_get, self, 79c1be0bf0SDmitry Bogdanov rbl_status, 80c1be0bf0SDmitry Bogdanov ((rbl_status & AQ_A2_BOOT_STARTED) && 81c1be0bf0SDmitry Bogdanov (rbl_status != 0xFFFFFFFFu)), 82c1be0bf0SDmitry Bogdanov 10, 500000); 83c1be0bf0SDmitry Bogdanov if (err) 84c1be0bf0SDmitry Bogdanov aq_pr_trace("Boot code probably hanged, reboot anyway"); 85c1be0bf0SDmitry Bogdanov 86c1be0bf0SDmitry Bogdanov hw_atl2_mif_host_req_int_clr(self, 0x01); 87c1be0bf0SDmitry Bogdanov rbl_request = AQ_A2_FW_BOOT_REQ_REBOOT; 88c1be0bf0SDmitry Bogdanov #ifdef AQ_CFG_FAST_START 89c1be0bf0SDmitry Bogdanov rbl_request |= AQ_A2_FW_BOOT_REQ_MAC_FAST_BOOT; 90c1be0bf0SDmitry Bogdanov #endif 91c1be0bf0SDmitry Bogdanov hw_atl2_mif_mcp_boot_reg_set(self, rbl_request); 92c1be0bf0SDmitry Bogdanov 93c1be0bf0SDmitry Bogdanov /* Wait for RBL boot */ 94c1be0bf0SDmitry Bogdanov err = readx_poll_timeout_atomic(hw_atl2_mif_mcp_boot_reg_get, self, 95c1be0bf0SDmitry Bogdanov rbl_status, 96c1be0bf0SDmitry Bogdanov ((rbl_status & AQ_A2_BOOT_STARTED) && 97c1be0bf0SDmitry Bogdanov (rbl_status != 0xFFFFFFFFu)), 98c1be0bf0SDmitry Bogdanov 10, 200000); 99c1be0bf0SDmitry Bogdanov if (err) { 100c1be0bf0SDmitry Bogdanov aq_pr_err("Boot code hanged"); 101c1be0bf0SDmitry Bogdanov goto err_exit; 102c1be0bf0SDmitry Bogdanov } 103c1be0bf0SDmitry Bogdanov 104c1be0bf0SDmitry Bogdanov err = readx_poll_timeout_atomic(hw_atl2_mcp_boot_complete, self, 105c1be0bf0SDmitry Bogdanov rbl_complete, 106c1be0bf0SDmitry Bogdanov rbl_complete, 107c1be0bf0SDmitry Bogdanov 10, 2000000); 108c1be0bf0SDmitry Bogdanov 109c1be0bf0SDmitry Bogdanov if (err) { 110c1be0bf0SDmitry Bogdanov aq_pr_err("FW Restart timed out"); 111c1be0bf0SDmitry Bogdanov goto err_exit; 112c1be0bf0SDmitry Bogdanov } 113c1be0bf0SDmitry Bogdanov 114c1be0bf0SDmitry Bogdanov rbl_status = hw_atl2_mif_mcp_boot_reg_get(self); 115c1be0bf0SDmitry Bogdanov 116c1be0bf0SDmitry Bogdanov if (rbl_status & AQ_A2_FW_BOOT_FAILED_MASK) { 117c1be0bf0SDmitry Bogdanov err = -EIO; 118c1be0bf0SDmitry Bogdanov aq_pr_err("FW Restart failed"); 119c1be0bf0SDmitry Bogdanov goto err_exit; 120c1be0bf0SDmitry Bogdanov } 121c1be0bf0SDmitry Bogdanov 122c1be0bf0SDmitry Bogdanov if (hw_atl2_mif_host_req_int_get(self) & 123c1be0bf0SDmitry Bogdanov HW_ATL2_MCP_HOST_REQ_INT_READY) { 124c1be0bf0SDmitry Bogdanov err = -EIO; 125c1be0bf0SDmitry Bogdanov aq_pr_err("No FW detected. Dynamic FW load not implemented"); 126c1be0bf0SDmitry Bogdanov goto err_exit; 127c1be0bf0SDmitry Bogdanov } 128c1be0bf0SDmitry Bogdanov 129c1be0bf0SDmitry Bogdanov if (self->aq_fw_ops) { 130c1be0bf0SDmitry Bogdanov err = self->aq_fw_ops->init(self); 131c1be0bf0SDmitry Bogdanov if (err) { 132c1be0bf0SDmitry Bogdanov aq_pr_err("FW Init failed"); 133c1be0bf0SDmitry Bogdanov goto err_exit; 134c1be0bf0SDmitry Bogdanov } 135c1be0bf0SDmitry Bogdanov } 136c1be0bf0SDmitry Bogdanov 137c1be0bf0SDmitry Bogdanov err_exit: 138c1be0bf0SDmitry Bogdanov return err; 139c1be0bf0SDmitry Bogdanov } 140