1b843c749SSergey Zigachev /* 2b843c749SSergey Zigachev * Copyright 2016 Advanced Micro Devices, Inc. 3b843c749SSergey Zigachev * 4b843c749SSergey Zigachev * Permission is hereby granted, free of charge, to any person obtaining a 5b843c749SSergey Zigachev * copy of this software and associated documentation files (the "Software"), 6b843c749SSergey Zigachev * to deal in the Software without restriction, including without limitation 7b843c749SSergey Zigachev * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8b843c749SSergey Zigachev * and/or sell copies of the Software, and to permit persons to whom the 9b843c749SSergey Zigachev * Software is furnished to do so, subject to the following conditions: 10b843c749SSergey Zigachev * 11b843c749SSergey Zigachev * The above copyright notice and this permission notice shall be included in 12b843c749SSergey Zigachev * all copies or substantial portions of the Software. 13b843c749SSergey Zigachev * 14b843c749SSergey Zigachev * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15b843c749SSergey Zigachev * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16b843c749SSergey Zigachev * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17b843c749SSergey Zigachev * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18b843c749SSergey Zigachev * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19b843c749SSergey Zigachev * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20b843c749SSergey Zigachev * OTHER DEALINGS IN THE SOFTWARE. 21b843c749SSergey Zigachev * 22b843c749SSergey Zigachev * Author: Huang Rui 23b843c749SSergey Zigachev * 24b843c749SSergey Zigachev */ 25b843c749SSergey Zigachev 26b843c749SSergey Zigachev #include <linux/firmware.h> 27b843c749SSergey Zigachev #include <drm/drmP.h> 28b843c749SSergey Zigachev #include "amdgpu.h" 29b843c749SSergey Zigachev #include "amdgpu_psp.h" 30b843c749SSergey Zigachev #include "amdgpu_ucode.h" 31b843c749SSergey Zigachev #include "soc15_common.h" 32b843c749SSergey Zigachev #include "psp_v3_1.h" 33b843c749SSergey Zigachev 34b843c749SSergey Zigachev #include "mp/mp_9_0_offset.h" 35b843c749SSergey Zigachev #include "mp/mp_9_0_sh_mask.h" 36b843c749SSergey Zigachev #include "gc/gc_9_0_offset.h" 37b843c749SSergey Zigachev #include "sdma0/sdma0_4_0_offset.h" 38b843c749SSergey Zigachev #include "nbio/nbio_6_1_offset.h" 39b843c749SSergey Zigachev 40b843c749SSergey Zigachev MODULE_FIRMWARE("amdgpu/vega10_sos.bin"); 41b843c749SSergey Zigachev MODULE_FIRMWARE("amdgpu/vega10_asd.bin"); 42b843c749SSergey Zigachev MODULE_FIRMWARE("amdgpu/vega12_sos.bin"); 43b843c749SSergey Zigachev MODULE_FIRMWARE("amdgpu/vega12_asd.bin"); 44b843c749SSergey Zigachev MODULE_FIRMWARE("amdgpu/vega20_sos.bin"); 45b843c749SSergey Zigachev MODULE_FIRMWARE("amdgpu/vega20_asd.bin"); 46b843c749SSergey Zigachev 47b843c749SSergey Zigachev 48b843c749SSergey Zigachev #define smnMP1_FIRMWARE_FLAGS 0x3010028 49b843c749SSergey Zigachev 50b843c749SSergey Zigachev static uint32_t sos_old_versions[] = {1517616, 1510592, 1448594, 1446554}; 51b843c749SSergey Zigachev 52b843c749SSergey Zigachev static int 53b843c749SSergey Zigachev psp_v3_1_get_fw_type(struct amdgpu_firmware_info *ucode, enum psp_gfx_fw_type *type) 54b843c749SSergey Zigachev { 55b843c749SSergey Zigachev switch(ucode->ucode_id) { 56b843c749SSergey Zigachev case AMDGPU_UCODE_ID_SDMA0: 57b843c749SSergey Zigachev *type = GFX_FW_TYPE_SDMA0; 58b843c749SSergey Zigachev break; 59b843c749SSergey Zigachev case AMDGPU_UCODE_ID_SDMA1: 60b843c749SSergey Zigachev *type = GFX_FW_TYPE_SDMA1; 61b843c749SSergey Zigachev break; 62b843c749SSergey Zigachev case AMDGPU_UCODE_ID_CP_CE: 63b843c749SSergey Zigachev *type = GFX_FW_TYPE_CP_CE; 64b843c749SSergey Zigachev break; 65b843c749SSergey Zigachev case AMDGPU_UCODE_ID_CP_PFP: 66b843c749SSergey Zigachev *type = GFX_FW_TYPE_CP_PFP; 67b843c749SSergey Zigachev break; 68b843c749SSergey Zigachev case AMDGPU_UCODE_ID_CP_ME: 69b843c749SSergey Zigachev *type = GFX_FW_TYPE_CP_ME; 70b843c749SSergey Zigachev break; 71b843c749SSergey Zigachev case AMDGPU_UCODE_ID_CP_MEC1: 72b843c749SSergey Zigachev *type = GFX_FW_TYPE_CP_MEC; 73b843c749SSergey Zigachev break; 74b843c749SSergey Zigachev case AMDGPU_UCODE_ID_CP_MEC1_JT: 75b843c749SSergey Zigachev *type = GFX_FW_TYPE_CP_MEC_ME1; 76b843c749SSergey Zigachev break; 77b843c749SSergey Zigachev case AMDGPU_UCODE_ID_CP_MEC2: 78b843c749SSergey Zigachev *type = GFX_FW_TYPE_CP_MEC; 79b843c749SSergey Zigachev break; 80b843c749SSergey Zigachev case AMDGPU_UCODE_ID_CP_MEC2_JT: 81b843c749SSergey Zigachev *type = GFX_FW_TYPE_CP_MEC_ME2; 82b843c749SSergey Zigachev break; 83b843c749SSergey Zigachev case AMDGPU_UCODE_ID_RLC_G: 84b843c749SSergey Zigachev *type = GFX_FW_TYPE_RLC_G; 85b843c749SSergey Zigachev break; 86b843c749SSergey Zigachev case AMDGPU_UCODE_ID_SMC: 87b843c749SSergey Zigachev *type = GFX_FW_TYPE_SMU; 88b843c749SSergey Zigachev break; 89b843c749SSergey Zigachev case AMDGPU_UCODE_ID_UVD: 90b843c749SSergey Zigachev *type = GFX_FW_TYPE_UVD; 91b843c749SSergey Zigachev break; 92b843c749SSergey Zigachev case AMDGPU_UCODE_ID_VCE: 93b843c749SSergey Zigachev *type = GFX_FW_TYPE_VCE; 94b843c749SSergey Zigachev break; 95b843c749SSergey Zigachev case AMDGPU_UCODE_ID_MAXIMUM: 96b843c749SSergey Zigachev default: 97b843c749SSergey Zigachev return -EINVAL; 98b843c749SSergey Zigachev } 99b843c749SSergey Zigachev 100b843c749SSergey Zigachev return 0; 101b843c749SSergey Zigachev } 102b843c749SSergey Zigachev 103b843c749SSergey Zigachev static int psp_v3_1_init_microcode(struct psp_context *psp) 104b843c749SSergey Zigachev { 105b843c749SSergey Zigachev struct amdgpu_device *adev = psp->adev; 106b843c749SSergey Zigachev const char *chip_name; 107b843c749SSergey Zigachev char fw_name[30]; 108b843c749SSergey Zigachev int err = 0; 109b843c749SSergey Zigachev const struct psp_firmware_header_v1_0 *hdr; 110b843c749SSergey Zigachev 111b843c749SSergey Zigachev DRM_DEBUG("\n"); 112b843c749SSergey Zigachev 113b843c749SSergey Zigachev switch (adev->asic_type) { 114b843c749SSergey Zigachev case CHIP_VEGA10: 115b843c749SSergey Zigachev chip_name = "vega10"; 116b843c749SSergey Zigachev break; 117b843c749SSergey Zigachev case CHIP_VEGA12: 118b843c749SSergey Zigachev chip_name = "vega12"; 119b843c749SSergey Zigachev break; 120b843c749SSergey Zigachev default: BUG(); 121b843c749SSergey Zigachev } 122b843c749SSergey Zigachev 123b843c749SSergey Zigachev snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sos.bin", chip_name); 124b843c749SSergey Zigachev err = request_firmware(&adev->psp.sos_fw, fw_name, adev->dev); 125b843c749SSergey Zigachev if (err) 126b843c749SSergey Zigachev goto out; 127b843c749SSergey Zigachev 128b843c749SSergey Zigachev err = amdgpu_ucode_validate(adev->psp.sos_fw); 129b843c749SSergey Zigachev if (err) 130b843c749SSergey Zigachev goto out; 131b843c749SSergey Zigachev 132b843c749SSergey Zigachev hdr = (const struct psp_firmware_header_v1_0 *)adev->psp.sos_fw->data; 133b843c749SSergey Zigachev adev->psp.sos_fw_version = le32_to_cpu(hdr->header.ucode_version); 134b843c749SSergey Zigachev adev->psp.sos_feature_version = le32_to_cpu(hdr->ucode_feature_version); 135b843c749SSergey Zigachev adev->psp.sos_bin_size = le32_to_cpu(hdr->sos_size_bytes); 136b843c749SSergey Zigachev adev->psp.sys_bin_size = le32_to_cpu(hdr->header.ucode_size_bytes) - 137b843c749SSergey Zigachev le32_to_cpu(hdr->sos_size_bytes); 138b843c749SSergey Zigachev adev->psp.sys_start_addr = (uint8_t *)hdr + 139b843c749SSergey Zigachev le32_to_cpu(hdr->header.ucode_array_offset_bytes); 140b843c749SSergey Zigachev adev->psp.sos_start_addr = (uint8_t *)adev->psp.sys_start_addr + 141b843c749SSergey Zigachev le32_to_cpu(hdr->sos_offset_bytes); 142b843c749SSergey Zigachev 143b843c749SSergey Zigachev snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_asd.bin", chip_name); 144b843c749SSergey Zigachev err = request_firmware(&adev->psp.asd_fw, fw_name, adev->dev); 145b843c749SSergey Zigachev if (err) 146b843c749SSergey Zigachev goto out; 147b843c749SSergey Zigachev 148b843c749SSergey Zigachev err = amdgpu_ucode_validate(adev->psp.asd_fw); 149b843c749SSergey Zigachev if (err) 150b843c749SSergey Zigachev goto out; 151b843c749SSergey Zigachev 152b843c749SSergey Zigachev hdr = (const struct psp_firmware_header_v1_0 *)adev->psp.asd_fw->data; 153b843c749SSergey Zigachev adev->psp.asd_fw_version = le32_to_cpu(hdr->header.ucode_version); 154b843c749SSergey Zigachev adev->psp.asd_feature_version = le32_to_cpu(hdr->ucode_feature_version); 155b843c749SSergey Zigachev adev->psp.asd_ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes); 156b843c749SSergey Zigachev adev->psp.asd_start_addr = (uint8_t *)hdr + 157b843c749SSergey Zigachev le32_to_cpu(hdr->header.ucode_array_offset_bytes); 158b843c749SSergey Zigachev 159b843c749SSergey Zigachev return 0; 160b843c749SSergey Zigachev out: 161b843c749SSergey Zigachev if (err) { 162b843c749SSergey Zigachev dev_err(adev->dev, 163b843c749SSergey Zigachev "psp v3.1: Failed to load firmware \"%s\"\n", 164b843c749SSergey Zigachev fw_name); 165b843c749SSergey Zigachev release_firmware(adev->psp.sos_fw); 166b843c749SSergey Zigachev adev->psp.sos_fw = NULL; 167b843c749SSergey Zigachev release_firmware(adev->psp.asd_fw); 168b843c749SSergey Zigachev adev->psp.asd_fw = NULL; 169b843c749SSergey Zigachev } 170b843c749SSergey Zigachev 171b843c749SSergey Zigachev return err; 172b843c749SSergey Zigachev } 173b843c749SSergey Zigachev 174b843c749SSergey Zigachev static int psp_v3_1_bootloader_load_sysdrv(struct psp_context *psp) 175b843c749SSergey Zigachev { 176b843c749SSergey Zigachev int ret; 177b843c749SSergey Zigachev uint32_t psp_gfxdrv_command_reg = 0; 178b843c749SSergey Zigachev struct amdgpu_device *adev = psp->adev; 179b843c749SSergey Zigachev uint32_t sol_reg; 180b843c749SSergey Zigachev 181b843c749SSergey Zigachev /* Check sOS sign of life register to confirm sys driver and sOS 182b843c749SSergey Zigachev * are already been loaded. 183b843c749SSergey Zigachev */ 184b843c749SSergey Zigachev sol_reg = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_81); 185b843c749SSergey Zigachev if (sol_reg) 186b843c749SSergey Zigachev return 0; 187b843c749SSergey Zigachev 188b843c749SSergey Zigachev /* Wait for bootloader to signify that is ready having bit 31 of C2PMSG_35 set to 1 */ 189b843c749SSergey Zigachev ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35), 190b843c749SSergey Zigachev 0x80000000, 0x80000000, false); 191b843c749SSergey Zigachev if (ret) 192b843c749SSergey Zigachev return ret; 193b843c749SSergey Zigachev 194b843c749SSergey Zigachev memset(psp->fw_pri_buf, 0, PSP_1_MEG); 195b843c749SSergey Zigachev 196b843c749SSergey Zigachev /* Copy PSP System Driver binary to memory */ 197b843c749SSergey Zigachev memcpy(psp->fw_pri_buf, psp->sys_start_addr, psp->sys_bin_size); 198b843c749SSergey Zigachev 199b843c749SSergey Zigachev /* Provide the sys driver to bootrom */ 200b843c749SSergey Zigachev WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36, 201b843c749SSergey Zigachev (uint32_t)(psp->fw_pri_mc_addr >> 20)); 202b843c749SSergey Zigachev psp_gfxdrv_command_reg = 1 << 16; 203b843c749SSergey Zigachev WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, 204b843c749SSergey Zigachev psp_gfxdrv_command_reg); 205b843c749SSergey Zigachev 206b843c749SSergey Zigachev /* there might be handshake issue with hardware which needs delay */ 207b843c749SSergey Zigachev mdelay(20); 208b843c749SSergey Zigachev 209b843c749SSergey Zigachev ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35), 210b843c749SSergey Zigachev 0x80000000, 0x80000000, false); 211b843c749SSergey Zigachev 212b843c749SSergey Zigachev return ret; 213b843c749SSergey Zigachev } 214b843c749SSergey Zigachev 215b843c749SSergey Zigachev static bool psp_v3_1_match_version(struct amdgpu_device *adev, uint32_t ver) 216b843c749SSergey Zigachev { 217b843c749SSergey Zigachev int i; 218b843c749SSergey Zigachev 219b843c749SSergey Zigachev if (ver == adev->psp.sos_fw_version) 220b843c749SSergey Zigachev return true; 221b843c749SSergey Zigachev 222b843c749SSergey Zigachev /* 223b843c749SSergey Zigachev * Double check if the latest four legacy versions. 224b843c749SSergey Zigachev * If yes, it is still the right version. 225b843c749SSergey Zigachev */ 226b843c749SSergey Zigachev for (i = 0; i < sizeof(sos_old_versions) / sizeof(uint32_t); i++) { 227b843c749SSergey Zigachev if (sos_old_versions[i] == adev->psp.sos_fw_version) 228b843c749SSergey Zigachev return true; 229b843c749SSergey Zigachev } 230b843c749SSergey Zigachev 231b843c749SSergey Zigachev return false; 232b843c749SSergey Zigachev } 233b843c749SSergey Zigachev 234b843c749SSergey Zigachev static int psp_v3_1_bootloader_load_sos(struct psp_context *psp) 235b843c749SSergey Zigachev { 236b843c749SSergey Zigachev int ret; 237b843c749SSergey Zigachev unsigned int psp_gfxdrv_command_reg = 0; 238b843c749SSergey Zigachev struct amdgpu_device *adev = psp->adev; 239b843c749SSergey Zigachev uint32_t sol_reg, ver; 240b843c749SSergey Zigachev 241b843c749SSergey Zigachev /* Check sOS sign of life register to confirm sys driver and sOS 242b843c749SSergey Zigachev * are already been loaded. 243b843c749SSergey Zigachev */ 244b843c749SSergey Zigachev sol_reg = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_81); 245b843c749SSergey Zigachev if (sol_reg) 246b843c749SSergey Zigachev return 0; 247b843c749SSergey Zigachev 248b843c749SSergey Zigachev /* Wait for bootloader to signify that is ready having bit 31 of C2PMSG_35 set to 1 */ 249b843c749SSergey Zigachev ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35), 250b843c749SSergey Zigachev 0x80000000, 0x80000000, false); 251b843c749SSergey Zigachev if (ret) 252b843c749SSergey Zigachev return ret; 253b843c749SSergey Zigachev 254b843c749SSergey Zigachev memset(psp->fw_pri_buf, 0, PSP_1_MEG); 255b843c749SSergey Zigachev 256b843c749SSergey Zigachev /* Copy Secure OS binary to PSP memory */ 257b843c749SSergey Zigachev memcpy(psp->fw_pri_buf, psp->sos_start_addr, psp->sos_bin_size); 258b843c749SSergey Zigachev 259b843c749SSergey Zigachev /* Provide the PSP secure OS to bootrom */ 260b843c749SSergey Zigachev WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36, 261b843c749SSergey Zigachev (uint32_t)(psp->fw_pri_mc_addr >> 20)); 262b843c749SSergey Zigachev psp_gfxdrv_command_reg = 2 << 16; 263b843c749SSergey Zigachev WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, 264b843c749SSergey Zigachev psp_gfxdrv_command_reg); 265b843c749SSergey Zigachev 266b843c749SSergey Zigachev /* there might be handshake issue with hardware which needs delay */ 267b843c749SSergey Zigachev mdelay(20); 268b843c749SSergey Zigachev ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_81), 269b843c749SSergey Zigachev RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_81), 270b843c749SSergey Zigachev 0, true); 271b843c749SSergey Zigachev 272b843c749SSergey Zigachev ver = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_58); 273b843c749SSergey Zigachev if (!psp_v3_1_match_version(adev, ver)) 274b843c749SSergey Zigachev DRM_WARN("SOS version doesn't match\n"); 275b843c749SSergey Zigachev 276b843c749SSergey Zigachev return ret; 277b843c749SSergey Zigachev } 278b843c749SSergey Zigachev 279b843c749SSergey Zigachev static int psp_v3_1_prep_cmd_buf(struct amdgpu_firmware_info *ucode, 280b843c749SSergey Zigachev struct psp_gfx_cmd_resp *cmd) 281b843c749SSergey Zigachev { 282b843c749SSergey Zigachev int ret; 283b843c749SSergey Zigachev uint64_t fw_mem_mc_addr = ucode->mc_addr; 284b843c749SSergey Zigachev 285b843c749SSergey Zigachev memset(cmd, 0, sizeof(struct psp_gfx_cmd_resp)); 286b843c749SSergey Zigachev 287b843c749SSergey Zigachev cmd->cmd_id = GFX_CMD_ID_LOAD_IP_FW; 288b843c749SSergey Zigachev cmd->cmd.cmd_load_ip_fw.fw_phy_addr_lo = lower_32_bits(fw_mem_mc_addr); 289b843c749SSergey Zigachev cmd->cmd.cmd_load_ip_fw.fw_phy_addr_hi = upper_32_bits(fw_mem_mc_addr); 290b843c749SSergey Zigachev cmd->cmd.cmd_load_ip_fw.fw_size = ucode->ucode_size; 291b843c749SSergey Zigachev 292b843c749SSergey Zigachev ret = psp_v3_1_get_fw_type(ucode, &cmd->cmd.cmd_load_ip_fw.fw_type); 293b843c749SSergey Zigachev if (ret) 294b843c749SSergey Zigachev DRM_ERROR("Unknown firmware type\n"); 295b843c749SSergey Zigachev 296b843c749SSergey Zigachev return ret; 297b843c749SSergey Zigachev } 298b843c749SSergey Zigachev 299b843c749SSergey Zigachev static int psp_v3_1_ring_init(struct psp_context *psp, 300b843c749SSergey Zigachev enum psp_ring_type ring_type) 301b843c749SSergey Zigachev { 302b843c749SSergey Zigachev int ret = 0; 303b843c749SSergey Zigachev struct psp_ring *ring; 304b843c749SSergey Zigachev struct amdgpu_device *adev = psp->adev; 305b843c749SSergey Zigachev 306b843c749SSergey Zigachev ring = &psp->km_ring; 307b843c749SSergey Zigachev 308b843c749SSergey Zigachev ring->ring_type = ring_type; 309b843c749SSergey Zigachev 310b843c749SSergey Zigachev /* allocate 4k Page of Local Frame Buffer memory for ring */ 311b843c749SSergey Zigachev ring->ring_size = 0x1000; 312b843c749SSergey Zigachev ret = amdgpu_bo_create_kernel(adev, ring->ring_size, PAGE_SIZE, 313b843c749SSergey Zigachev AMDGPU_GEM_DOMAIN_VRAM, 314b843c749SSergey Zigachev &adev->firmware.rbuf, 315*78973132SSergey Zigachev (u64 *)&ring->ring_mem_mc_addr, 316b843c749SSergey Zigachev (void **)&ring->ring_mem); 317b843c749SSergey Zigachev if (ret) { 318b843c749SSergey Zigachev ring->ring_size = 0; 319b843c749SSergey Zigachev return ret; 320b843c749SSergey Zigachev } 321b843c749SSergey Zigachev 322b843c749SSergey Zigachev return 0; 323b843c749SSergey Zigachev } 324b843c749SSergey Zigachev 325b843c749SSergey Zigachev static int psp_v3_1_ring_create(struct psp_context *psp, 326b843c749SSergey Zigachev enum psp_ring_type ring_type) 327b843c749SSergey Zigachev { 328b843c749SSergey Zigachev int ret = 0; 329b843c749SSergey Zigachev unsigned int psp_ring_reg = 0; 330b843c749SSergey Zigachev struct psp_ring *ring = &psp->km_ring; 331b843c749SSergey Zigachev struct amdgpu_device *adev = psp->adev; 332b843c749SSergey Zigachev 333b843c749SSergey Zigachev /* Write low address of the ring to C2PMSG_69 */ 334b843c749SSergey Zigachev psp_ring_reg = lower_32_bits(ring->ring_mem_mc_addr); 335b843c749SSergey Zigachev WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_69, psp_ring_reg); 336b843c749SSergey Zigachev /* Write high address of the ring to C2PMSG_70 */ 337b843c749SSergey Zigachev psp_ring_reg = upper_32_bits(ring->ring_mem_mc_addr); 338b843c749SSergey Zigachev WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_70, psp_ring_reg); 339b843c749SSergey Zigachev /* Write size of ring to C2PMSG_71 */ 340b843c749SSergey Zigachev psp_ring_reg = ring->ring_size; 341b843c749SSergey Zigachev WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_71, psp_ring_reg); 342b843c749SSergey Zigachev /* Write the ring initialization command to C2PMSG_64 */ 343b843c749SSergey Zigachev psp_ring_reg = ring_type; 344b843c749SSergey Zigachev psp_ring_reg = psp_ring_reg << 16; 345b843c749SSergey Zigachev WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_64, psp_ring_reg); 346b843c749SSergey Zigachev 347b843c749SSergey Zigachev /* there might be handshake issue with hardware which needs delay */ 348b843c749SSergey Zigachev mdelay(20); 349b843c749SSergey Zigachev 350b843c749SSergey Zigachev /* Wait for response flag (bit 31) in C2PMSG_64 */ 351b843c749SSergey Zigachev ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64), 352b843c749SSergey Zigachev 0x80000000, 0x8000FFFF, false); 353b843c749SSergey Zigachev 354b843c749SSergey Zigachev return ret; 355b843c749SSergey Zigachev } 356b843c749SSergey Zigachev 357b843c749SSergey Zigachev static int psp_v3_1_ring_stop(struct psp_context *psp, 358b843c749SSergey Zigachev enum psp_ring_type ring_type) 359b843c749SSergey Zigachev { 360b843c749SSergey Zigachev int ret = 0; 361b843c749SSergey Zigachev struct psp_ring *ring; 362b843c749SSergey Zigachev unsigned int psp_ring_reg = 0; 363b843c749SSergey Zigachev struct amdgpu_device *adev = psp->adev; 364b843c749SSergey Zigachev 365b843c749SSergey Zigachev ring = &psp->km_ring; 366b843c749SSergey Zigachev 367b843c749SSergey Zigachev /* Write the ring destroy command to C2PMSG_64 */ 368b843c749SSergey Zigachev psp_ring_reg = 3 << 16; 369b843c749SSergey Zigachev WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_64, psp_ring_reg); 370b843c749SSergey Zigachev 371b843c749SSergey Zigachev /* there might be handshake issue with hardware which needs delay */ 372b843c749SSergey Zigachev mdelay(20); 373b843c749SSergey Zigachev 374b843c749SSergey Zigachev /* Wait for response flag (bit 31) in C2PMSG_64 */ 375b843c749SSergey Zigachev ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64), 376b843c749SSergey Zigachev 0x80000000, 0x80000000, false); 377b843c749SSergey Zigachev 378b843c749SSergey Zigachev return ret; 379b843c749SSergey Zigachev } 380b843c749SSergey Zigachev 381b843c749SSergey Zigachev static int psp_v3_1_ring_destroy(struct psp_context *psp, 382b843c749SSergey Zigachev enum psp_ring_type ring_type) 383b843c749SSergey Zigachev { 384b843c749SSergey Zigachev int ret = 0; 385b843c749SSergey Zigachev struct psp_ring *ring = &psp->km_ring; 386b843c749SSergey Zigachev struct amdgpu_device *adev = psp->adev; 387b843c749SSergey Zigachev 388b843c749SSergey Zigachev ret = psp_v3_1_ring_stop(psp, ring_type); 389b843c749SSergey Zigachev if (ret) 390b843c749SSergey Zigachev DRM_ERROR("Fail to stop psp ring\n"); 391b843c749SSergey Zigachev 392b843c749SSergey Zigachev amdgpu_bo_free_kernel(&adev->firmware.rbuf, 393*78973132SSergey Zigachev (u64 *)&ring->ring_mem_mc_addr, 394b843c749SSergey Zigachev (void **)&ring->ring_mem); 395b843c749SSergey Zigachev 396b843c749SSergey Zigachev return ret; 397b843c749SSergey Zigachev } 398b843c749SSergey Zigachev 399b843c749SSergey Zigachev static int psp_v3_1_cmd_submit(struct psp_context *psp, 400b843c749SSergey Zigachev struct amdgpu_firmware_info *ucode, 401b843c749SSergey Zigachev uint64_t cmd_buf_mc_addr, uint64_t fence_mc_addr, 402b843c749SSergey Zigachev int index) 403b843c749SSergey Zigachev { 404b843c749SSergey Zigachev unsigned int psp_write_ptr_reg = 0; 405b843c749SSergey Zigachev struct psp_gfx_rb_frame * write_frame = psp->km_ring.ring_mem; 406b843c749SSergey Zigachev struct psp_ring *ring = &psp->km_ring; 407b843c749SSergey Zigachev struct psp_gfx_rb_frame *ring_buffer_start = ring->ring_mem; 408b843c749SSergey Zigachev struct psp_gfx_rb_frame *ring_buffer_end = ring_buffer_start + 409b843c749SSergey Zigachev ring->ring_size / sizeof(struct psp_gfx_rb_frame) - 1; 410b843c749SSergey Zigachev struct amdgpu_device *adev = psp->adev; 411b843c749SSergey Zigachev uint32_t ring_size_dw = ring->ring_size / 4; 412b843c749SSergey Zigachev uint32_t rb_frame_size_dw = sizeof(struct psp_gfx_rb_frame) / 4; 413b843c749SSergey Zigachev 414b843c749SSergey Zigachev /* KM (GPCOM) prepare write pointer */ 415b843c749SSergey Zigachev psp_write_ptr_reg = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_67); 416b843c749SSergey Zigachev 417b843c749SSergey Zigachev /* Update KM RB frame pointer to new frame */ 418b843c749SSergey Zigachev /* write_frame ptr increments by size of rb_frame in bytes */ 419b843c749SSergey Zigachev /* psp_write_ptr_reg increments by size of rb_frame in DWORDs */ 420b843c749SSergey Zigachev if ((psp_write_ptr_reg % ring_size_dw) == 0) 421b843c749SSergey Zigachev write_frame = ring_buffer_start; 422b843c749SSergey Zigachev else 423b843c749SSergey Zigachev write_frame = ring_buffer_start + (psp_write_ptr_reg / rb_frame_size_dw); 424b843c749SSergey Zigachev /* Check invalid write_frame ptr address */ 425b843c749SSergey Zigachev if ((write_frame < ring_buffer_start) || (ring_buffer_end < write_frame)) { 426b843c749SSergey Zigachev DRM_ERROR("ring_buffer_start = %p; ring_buffer_end = %p; write_frame = %p\n", 427b843c749SSergey Zigachev ring_buffer_start, ring_buffer_end, write_frame); 428b843c749SSergey Zigachev DRM_ERROR("write_frame is pointing to address out of bounds\n"); 429b843c749SSergey Zigachev return -EINVAL; 430b843c749SSergey Zigachev } 431b843c749SSergey Zigachev 432b843c749SSergey Zigachev /* Initialize KM RB frame */ 433b843c749SSergey Zigachev memset(write_frame, 0, sizeof(struct psp_gfx_rb_frame)); 434b843c749SSergey Zigachev 435b843c749SSergey Zigachev /* Update KM RB frame */ 436b843c749SSergey Zigachev write_frame->cmd_buf_addr_hi = upper_32_bits(cmd_buf_mc_addr); 437b843c749SSergey Zigachev write_frame->cmd_buf_addr_lo = lower_32_bits(cmd_buf_mc_addr); 438b843c749SSergey Zigachev write_frame->fence_addr_hi = upper_32_bits(fence_mc_addr); 439b843c749SSergey Zigachev write_frame->fence_addr_lo = lower_32_bits(fence_mc_addr); 440b843c749SSergey Zigachev write_frame->fence_value = index; 441b843c749SSergey Zigachev 442b843c749SSergey Zigachev /* Update the write Pointer in DWORDs */ 443b843c749SSergey Zigachev psp_write_ptr_reg = (psp_write_ptr_reg + rb_frame_size_dw) % ring_size_dw; 444b843c749SSergey Zigachev WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_67, psp_write_ptr_reg); 445b843c749SSergey Zigachev 446b843c749SSergey Zigachev return 0; 447b843c749SSergey Zigachev } 448b843c749SSergey Zigachev 449b843c749SSergey Zigachev static int 450b843c749SSergey Zigachev psp_v3_1_sram_map(struct amdgpu_device *adev, 451b843c749SSergey Zigachev unsigned int *sram_offset, unsigned int *sram_addr_reg_offset, 452b843c749SSergey Zigachev unsigned int *sram_data_reg_offset, 453b843c749SSergey Zigachev enum AMDGPU_UCODE_ID ucode_id) 454b843c749SSergey Zigachev { 455b843c749SSergey Zigachev int ret = 0; 456b843c749SSergey Zigachev 457b843c749SSergey Zigachev switch(ucode_id) { 458b843c749SSergey Zigachev /* TODO: needs to confirm */ 459b843c749SSergey Zigachev #if 0 460b843c749SSergey Zigachev case AMDGPU_UCODE_ID_SMC: 461b843c749SSergey Zigachev *sram_offset = 0; 462b843c749SSergey Zigachev *sram_addr_reg_offset = 0; 463b843c749SSergey Zigachev *sram_data_reg_offset = 0; 464b843c749SSergey Zigachev break; 465b843c749SSergey Zigachev #endif 466b843c749SSergey Zigachev 467b843c749SSergey Zigachev case AMDGPU_UCODE_ID_CP_CE: 468b843c749SSergey Zigachev *sram_offset = 0x0; 469b843c749SSergey Zigachev *sram_addr_reg_offset = SOC15_REG_OFFSET(GC, 0, mmCP_CE_UCODE_ADDR); 470b843c749SSergey Zigachev *sram_data_reg_offset = SOC15_REG_OFFSET(GC, 0, mmCP_CE_UCODE_DATA); 471b843c749SSergey Zigachev break; 472b843c749SSergey Zigachev 473b843c749SSergey Zigachev case AMDGPU_UCODE_ID_CP_PFP: 474b843c749SSergey Zigachev *sram_offset = 0x0; 475b843c749SSergey Zigachev *sram_addr_reg_offset = SOC15_REG_OFFSET(GC, 0, mmCP_PFP_UCODE_ADDR); 476b843c749SSergey Zigachev *sram_data_reg_offset = SOC15_REG_OFFSET(GC, 0, mmCP_PFP_UCODE_DATA); 477b843c749SSergey Zigachev break; 478b843c749SSergey Zigachev 479b843c749SSergey Zigachev case AMDGPU_UCODE_ID_CP_ME: 480b843c749SSergey Zigachev *sram_offset = 0x0; 481b843c749SSergey Zigachev *sram_addr_reg_offset = SOC15_REG_OFFSET(GC, 0, mmCP_HYP_ME_UCODE_ADDR); 482b843c749SSergey Zigachev *sram_data_reg_offset = SOC15_REG_OFFSET(GC, 0, mmCP_HYP_ME_UCODE_DATA); 483b843c749SSergey Zigachev break; 484b843c749SSergey Zigachev 485b843c749SSergey Zigachev case AMDGPU_UCODE_ID_CP_MEC1: 486b843c749SSergey Zigachev *sram_offset = 0x10000; 487b843c749SSergey Zigachev *sram_addr_reg_offset = SOC15_REG_OFFSET(GC, 0, mmCP_MEC_ME1_UCODE_ADDR); 488b843c749SSergey Zigachev *sram_data_reg_offset = SOC15_REG_OFFSET(GC, 0, mmCP_MEC_ME1_UCODE_DATA); 489b843c749SSergey Zigachev break; 490b843c749SSergey Zigachev 491b843c749SSergey Zigachev case AMDGPU_UCODE_ID_CP_MEC2: 492b843c749SSergey Zigachev *sram_offset = 0x10000; 493b843c749SSergey Zigachev *sram_addr_reg_offset = SOC15_REG_OFFSET(GC, 0, mmCP_HYP_MEC2_UCODE_ADDR); 494b843c749SSergey Zigachev *sram_data_reg_offset = SOC15_REG_OFFSET(GC, 0, mmCP_HYP_MEC2_UCODE_DATA); 495b843c749SSergey Zigachev break; 496b843c749SSergey Zigachev 497b843c749SSergey Zigachev case AMDGPU_UCODE_ID_RLC_G: 498b843c749SSergey Zigachev *sram_offset = 0x2000; 499b843c749SSergey Zigachev *sram_addr_reg_offset = SOC15_REG_OFFSET(GC, 0, mmRLC_GPM_UCODE_ADDR); 500b843c749SSergey Zigachev *sram_data_reg_offset = SOC15_REG_OFFSET(GC, 0, mmRLC_GPM_UCODE_DATA); 501b843c749SSergey Zigachev break; 502b843c749SSergey Zigachev 503b843c749SSergey Zigachev case AMDGPU_UCODE_ID_SDMA0: 504b843c749SSergey Zigachev *sram_offset = 0x0; 505b843c749SSergey Zigachev *sram_addr_reg_offset = SOC15_REG_OFFSET(SDMA0, 0, mmSDMA0_UCODE_ADDR); 506b843c749SSergey Zigachev *sram_data_reg_offset = SOC15_REG_OFFSET(SDMA0, 0, mmSDMA0_UCODE_DATA); 507b843c749SSergey Zigachev break; 508b843c749SSergey Zigachev 509b843c749SSergey Zigachev /* TODO: needs to confirm */ 510b843c749SSergey Zigachev #if 0 511b843c749SSergey Zigachev case AMDGPU_UCODE_ID_SDMA1: 512b843c749SSergey Zigachev *sram_offset = ; 513b843c749SSergey Zigachev *sram_addr_reg_offset = ; 514b843c749SSergey Zigachev break; 515b843c749SSergey Zigachev 516b843c749SSergey Zigachev case AMDGPU_UCODE_ID_UVD: 517b843c749SSergey Zigachev *sram_offset = ; 518b843c749SSergey Zigachev *sram_addr_reg_offset = ; 519b843c749SSergey Zigachev break; 520b843c749SSergey Zigachev 521b843c749SSergey Zigachev case AMDGPU_UCODE_ID_VCE: 522b843c749SSergey Zigachev *sram_offset = ; 523b843c749SSergey Zigachev *sram_addr_reg_offset = ; 524b843c749SSergey Zigachev break; 525b843c749SSergey Zigachev #endif 526b843c749SSergey Zigachev 527b843c749SSergey Zigachev case AMDGPU_UCODE_ID_MAXIMUM: 528b843c749SSergey Zigachev default: 529b843c749SSergey Zigachev ret = -EINVAL; 530b843c749SSergey Zigachev break; 531b843c749SSergey Zigachev } 532b843c749SSergey Zigachev 533b843c749SSergey Zigachev return ret; 534b843c749SSergey Zigachev } 535b843c749SSergey Zigachev 536b843c749SSergey Zigachev static bool psp_v3_1_compare_sram_data(struct psp_context *psp, 537b843c749SSergey Zigachev struct amdgpu_firmware_info *ucode, 538b843c749SSergey Zigachev enum AMDGPU_UCODE_ID ucode_type) 539b843c749SSergey Zigachev { 540b843c749SSergey Zigachev int err = 0; 541b843c749SSergey Zigachev unsigned int fw_sram_reg_val = 0; 542b843c749SSergey Zigachev unsigned int fw_sram_addr_reg_offset = 0; 543b843c749SSergey Zigachev unsigned int fw_sram_data_reg_offset = 0; 544b843c749SSergey Zigachev unsigned int ucode_size; 545b843c749SSergey Zigachev uint32_t *ucode_mem = NULL; 546b843c749SSergey Zigachev struct amdgpu_device *adev = psp->adev; 547b843c749SSergey Zigachev 548b843c749SSergey Zigachev err = psp_v3_1_sram_map(adev, &fw_sram_reg_val, &fw_sram_addr_reg_offset, 549b843c749SSergey Zigachev &fw_sram_data_reg_offset, ucode_type); 550b843c749SSergey Zigachev if (err) 551b843c749SSergey Zigachev return false; 552b843c749SSergey Zigachev 553b843c749SSergey Zigachev WREG32(fw_sram_addr_reg_offset, fw_sram_reg_val); 554b843c749SSergey Zigachev 555b843c749SSergey Zigachev ucode_size = ucode->ucode_size; 556b843c749SSergey Zigachev ucode_mem = (uint32_t *)ucode->kaddr; 557b843c749SSergey Zigachev while (ucode_size) { 558b843c749SSergey Zigachev fw_sram_reg_val = RREG32(fw_sram_data_reg_offset); 559b843c749SSergey Zigachev 560b843c749SSergey Zigachev if (*ucode_mem != fw_sram_reg_val) 561b843c749SSergey Zigachev return false; 562b843c749SSergey Zigachev 563b843c749SSergey Zigachev ucode_mem++; 564b843c749SSergey Zigachev /* 4 bytes */ 565b843c749SSergey Zigachev ucode_size -= 4; 566b843c749SSergey Zigachev } 567b843c749SSergey Zigachev 568b843c749SSergey Zigachev return true; 569b843c749SSergey Zigachev } 570b843c749SSergey Zigachev 571b843c749SSergey Zigachev static bool psp_v3_1_smu_reload_quirk(struct psp_context *psp) 572b843c749SSergey Zigachev { 573b843c749SSergey Zigachev struct amdgpu_device *adev = psp->adev; 574b843c749SSergey Zigachev uint32_t reg; 575b843c749SSergey Zigachev 576b843c749SSergey Zigachev reg = smnMP1_FIRMWARE_FLAGS | 0x03b00000; 577b843c749SSergey Zigachev WREG32_SOC15(NBIO, 0, mmPCIE_INDEX2, reg); 578b843c749SSergey Zigachev reg = RREG32_SOC15(NBIO, 0, mmPCIE_DATA2); 579b843c749SSergey Zigachev return (reg & MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED_MASK) ? true : false; 580b843c749SSergey Zigachev } 581b843c749SSergey Zigachev 582b843c749SSergey Zigachev static int psp_v3_1_mode1_reset(struct psp_context *psp) 583b843c749SSergey Zigachev { 584b843c749SSergey Zigachev int ret; 585b843c749SSergey Zigachev uint32_t offset; 586b843c749SSergey Zigachev struct amdgpu_device *adev = psp->adev; 587b843c749SSergey Zigachev 588b843c749SSergey Zigachev offset = SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64); 589b843c749SSergey Zigachev 590b843c749SSergey Zigachev ret = psp_wait_for(psp, offset, 0x80000000, 0x8000FFFF, false); 591b843c749SSergey Zigachev 592b843c749SSergey Zigachev if (ret) { 593b843c749SSergey Zigachev DRM_INFO("psp is not working correctly before mode1 reset!\n"); 594b843c749SSergey Zigachev return -EINVAL; 595b843c749SSergey Zigachev } 596b843c749SSergey Zigachev 597b843c749SSergey Zigachev /*send the mode 1 reset command*/ 598b843c749SSergey Zigachev WREG32(offset, 0x70000); 599b843c749SSergey Zigachev 600b843c749SSergey Zigachev mdelay(1000); 601b843c749SSergey Zigachev 602b843c749SSergey Zigachev offset = SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_33); 603b843c749SSergey Zigachev 604b843c749SSergey Zigachev ret = psp_wait_for(psp, offset, 0x80000000, 0x80000000, false); 605b843c749SSergey Zigachev 606b843c749SSergey Zigachev if (ret) { 607b843c749SSergey Zigachev DRM_INFO("psp mode 1 reset failed!\n"); 608b843c749SSergey Zigachev return -EINVAL; 609b843c749SSergey Zigachev } 610b843c749SSergey Zigachev 611b843c749SSergey Zigachev DRM_INFO("psp mode1 reset succeed \n"); 612b843c749SSergey Zigachev 613b843c749SSergey Zigachev return 0; 614b843c749SSergey Zigachev } 615b843c749SSergey Zigachev 616b843c749SSergey Zigachev static const struct psp_funcs psp_v3_1_funcs = { 617b843c749SSergey Zigachev .init_microcode = psp_v3_1_init_microcode, 618b843c749SSergey Zigachev .bootloader_load_sysdrv = psp_v3_1_bootloader_load_sysdrv, 619b843c749SSergey Zigachev .bootloader_load_sos = psp_v3_1_bootloader_load_sos, 620b843c749SSergey Zigachev .prep_cmd_buf = psp_v3_1_prep_cmd_buf, 621b843c749SSergey Zigachev .ring_init = psp_v3_1_ring_init, 622b843c749SSergey Zigachev .ring_create = psp_v3_1_ring_create, 623b843c749SSergey Zigachev .ring_stop = psp_v3_1_ring_stop, 624b843c749SSergey Zigachev .ring_destroy = psp_v3_1_ring_destroy, 625b843c749SSergey Zigachev .cmd_submit = psp_v3_1_cmd_submit, 626b843c749SSergey Zigachev .compare_sram_data = psp_v3_1_compare_sram_data, 627b843c749SSergey Zigachev .smu_reload_quirk = psp_v3_1_smu_reload_quirk, 628b843c749SSergey Zigachev .mode1_reset = psp_v3_1_mode1_reset, 629b843c749SSergey Zigachev }; 630b843c749SSergey Zigachev 631b843c749SSergey Zigachev void psp_v3_1_set_psp_funcs(struct psp_context *psp) 632b843c749SSergey Zigachev { 633b843c749SSergey Zigachev psp->funcs = &psp_v3_1_funcs; 634b843c749SSergey Zigachev } 635