/* * Copyright 2014 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *
*/
/** * gmc_v8_0_init_microcode - load ucode images from disk * * @adev: amdgpu_device pointer * * Use the firmware interface to load the ucode images into * the driver (not loaded into hw). * Returns 0 on success, error on failure.
*/ staticint gmc_v8_0_init_microcode(struct amdgpu_device *adev)
{ constchar *chip_name; int err;
DRM_DEBUG("\n");
switch (adev->asic_type) { case CHIP_TONGA:
chip_name = "tonga"; break; case CHIP_POLARIS11: if (ASICID_IS_P21(adev->pdev->device, adev->pdev->revision) ||
ASICID_IS_P31(adev->pdev->device, adev->pdev->revision))
chip_name = "polaris11_k"; else
chip_name = "polaris11"; break; case CHIP_POLARIS10: if (ASICID_IS_P30(adev->pdev->device, adev->pdev->revision))
chip_name = "polaris10_k"; else
chip_name = "polaris10"; break; case CHIP_POLARIS12: if (ASICID_IS_P23(adev->pdev->device, adev->pdev->revision)) {
chip_name = "polaris12_k";
} else {
WREG32(mmMC_SEQ_IO_DEBUG_INDEX, ixMC_IO_DEBUG_UP_159); /* Polaris12 32bit ASIC needs a special MC firmware */ if (RREG32(mmMC_SEQ_IO_DEBUG_DATA) == 0x05b4dc40)
chip_name = "polaris12_32"; else
chip_name = "polaris12";
} break; case CHIP_FIJI: case CHIP_CARRIZO: case CHIP_STONEY: case CHIP_VEGAM: return 0; default: return -EINVAL;
}
/** * gmc_v8_0_tonga_mc_load_microcode - load tonga MC ucode into the hw * * @adev: amdgpu_device pointer * * Load the GDDR MC ucode into the hw (VI). * Returns 0 on success, error on failure.
*/ staticint gmc_v8_0_tonga_mc_load_microcode(struct amdgpu_device *adev)
{ conststruct mc_firmware_header_v1_0 *hdr; const __le32 *fw_data = NULL; const __le32 *io_mc_regs = NULL;
u32 running; int i, ucode_size, regs_size;
/* Skip MC ucode loading on SR-IOV capable boards. * vbios does this for us in asic_init in that case. * Skip MC ucode loading on VF, because hypervisor will do that * for this adaptor.
*/ if (amdgpu_sriov_bios(adev)) return 0;
if (running == 0) { /* reset the engine and set to writable */
WREG32(mmMC_SEQ_SUP_CNTL, 0x00000008);
WREG32(mmMC_SEQ_SUP_CNTL, 0x00000010);
/* load mc io regs */ for (i = 0; i < regs_size; i++) {
WREG32(mmMC_SEQ_IO_DEBUG_INDEX, le32_to_cpup(io_mc_regs++));
WREG32(mmMC_SEQ_IO_DEBUG_DATA, le32_to_cpup(io_mc_regs++));
} /* load the MC ucode */ for (i = 0; i < ucode_size; i++)
WREG32(mmMC_SEQ_SUP_PGM, le32_to_cpup(fw_data++));
/* put the engine back into the active state */
WREG32(mmMC_SEQ_SUP_CNTL, 0x00000008);
WREG32(mmMC_SEQ_SUP_CNTL, 0x00000004);
WREG32(mmMC_SEQ_SUP_CNTL, 0x00000001);
/* wait for training to complete */ for (i = 0; i < adev->usec_timeout; i++) { if (REG_GET_FIELD(RREG32(mmMC_SEQ_TRAIN_WAKEUP_CNTL),
MC_SEQ_TRAIN_WAKEUP_CNTL, TRAIN_DONE_D0)) break;
udelay(1);
} for (i = 0; i < adev->usec_timeout; i++) { if (REG_GET_FIELD(RREG32(mmMC_SEQ_TRAIN_WAKEUP_CNTL),
MC_SEQ_TRAIN_WAKEUP_CNTL, TRAIN_DONE_D1)) break;
udelay(1);
}
}
/* Skip MC ucode loading on SR-IOV capable boards. * vbios does this for us in asic_init in that case. * Skip MC ucode loading on VF, because hypervisor will do that * for this adaptor.
*/ if (amdgpu_sriov_bios(adev)) return 0;
data = RREG32(mmMC_SEQ_MISC0);
data &= ~(0x40);
WREG32(mmMC_SEQ_MISC0, data);
/* load mc io regs */ for (i = 0; i < regs_size; i++) {
WREG32(mmMC_SEQ_IO_DEBUG_INDEX, le32_to_cpup(io_mc_regs++));
WREG32(mmMC_SEQ_IO_DEBUG_DATA, le32_to_cpup(io_mc_regs++));
}
/* load the MC ucode */ for (i = 0; i < ucode_size; i++)
WREG32(mmMC_SEQ_SUP_PGM, le32_to_cpup(fw_data++));
/* put the engine back into the active state */
WREG32(mmMC_SEQ_SUP_CNTL, 0x00000008);
WREG32(mmMC_SEQ_SUP_CNTL, 0x00000004);
WREG32(mmMC_SEQ_SUP_CNTL, 0x00000001);
/* wait for training to complete */ for (i = 0; i < adev->usec_timeout; i++) {
data = RREG32(mmMC_SEQ_MISC0); if (data & 0x80) break;
udelay(1);
}
/** * gmc_v8_0_mc_program - program the GPU memory controller * * @adev: amdgpu_device pointer * * Set the location of vram, gart, and AGP in the GPU's * physical address space (VI).
*/ staticvoid gmc_v8_0_mc_program(struct amdgpu_device *adev)
{ struct amdgpu_ip_block *ip_block;
u32 tmp; int i, j;
/** * gmc_v8_0_mc_init - initialize the memory controller driver params * * @adev: amdgpu_device pointer * * Look up the amount of vram, vram width, and decide how to place * vram and gart within the GPU's physical address space (VI). * Returns 0 for success.
*/ staticint gmc_v8_0_mc_init(struct amdgpu_device *adev)
{ int r;
u32 tmp;
adev->gmc.vram_width = amdgpu_atombios_get_vram_width(adev); if (!adev->gmc.vram_width) { int chansize, numchan;
/* Get VRAM informations */
tmp = RREG32(mmMC_ARB_RAMCFG); if (REG_GET_FIELD(tmp, MC_ARB_RAMCFG, CHANSIZE))
chansize = 64; else
chansize = 32;
tmp = RREG32(mmMC_SHARED_CHMAP); switch (REG_GET_FIELD(tmp, MC_SHARED_CHMAP, NOOFCHAN)) { case 0: default:
numchan = 1; break; case 1:
numchan = 2; break; case 2:
numchan = 4; break; case 3:
numchan = 8; break; case 4:
numchan = 3; break; case 5:
numchan = 6; break; case 6:
numchan = 10; break; case 7:
numchan = 12; break; case 8:
numchan = 16; break;
}
adev->gmc.vram_width = numchan * chansize;
} /* size in MB on si */
tmp = RREG32(mmCONFIG_MEMSIZE); /* some boards may have garbage in the upper 16 bits */ if (tmp & 0xffff0000) {
DRM_INFO("Probable bad vram size: 0x%08x\n", tmp); if (tmp & 0xffff)
tmp &= 0xffff;
}
adev->gmc.mc_vram_size = tmp * 1024ULL * 1024ULL;
adev->gmc.real_vram_size = adev->gmc.mc_vram_size;
if (!(adev->flags & AMD_IS_APU)) {
r = amdgpu_device_resize_fb_bar(adev); if (r) return r;
}
adev->gmc.aper_base = pci_resource_start(adev->pdev, 0);
adev->gmc.aper_size = pci_resource_len(adev->pdev, 0);
/* set the gart size */ if (amdgpu_gart_size == -1) { switch (adev->asic_type) { case CHIP_POLARIS10: /* all engines support GPUVM */ case CHIP_POLARIS11: /* all engines support GPUVM */ case CHIP_POLARIS12: /* all engines support GPUVM */ case CHIP_VEGAM: /* all engines support GPUVM */ default:
adev->gmc.gart_size = 256ULL << 20; break; case CHIP_TONGA: /* UVD, VCE do not support GPUVM */ case CHIP_FIJI: /* UVD, VCE do not support GPUVM */ case CHIP_CARRIZO: /* UVD, VCE do not support GPUVM, DCE SG support */ case CHIP_STONEY: /* UVD does not support GPUVM, DCE SG support */
adev->gmc.gart_size = 1024ULL << 20; break;
}
} else {
adev->gmc.gart_size = (u64)amdgpu_gart_size << 20;
}
/** * gmc_v8_0_flush_gpu_tlb_pasid - tlb flush via pasid * * @adev: amdgpu_device pointer * @pasid: pasid to be flush * @flush_type: type of flush * @all_hub: flush all hubs * @inst: is used to select which instance of KIQ to use for the invalidation * * Flush the TLB for the requested pasid.
*/ staticvoid gmc_v8_0_flush_gpu_tlb_pasid(struct amdgpu_device *adev,
uint16_t pasid, uint32_t flush_type, bool all_hub, uint32_t inst)
{
u32 mask = 0x0; int vmid;
/* * GART * VMID 0 is the physical GPU addresses as used by the kernel. * VMIDs 1-15 are used for userspace clients and are handled * by the amdgpu vm/hsa code.
*/
/** * gmc_v8_0_flush_gpu_tlb - gart tlb flush callback * * @adev: amdgpu_device pointer * @vmid: vm instance to flush * @vmhub: which hub to flush * @flush_type: type of flush * * Flush the TLB for the requested page table (VI).
*/ staticvoid gmc_v8_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid,
uint32_t vmhub, uint32_t flush_type)
{ /* bits 0-15 are the VM contexts0-15 */
WREG32(mmVM_INVALIDATE_REQUEST, 1 << vmid);
}
/** * gmc_v8_0_gart_enable - gart enable * * @adev: amdgpu_device pointer * * This sets up the TLBs, programs the page tables for VMID0, * sets up the hw for VMIDs 1-15 which are allocated on * demand, and sets up the global locations for the LDS, GDS, * and GPUVM for FSA64 clients (VI). * Returns 0 for success, errors for failure.
*/ staticint gmc_v8_0_gart_enable(struct amdgpu_device *adev)
{
uint64_t table_addr;
u32 tmp, field; int i;
if (adev->gart.bo == NULL) {
dev_err(adev->dev, "No VRAM object for PCIE GART.\n"); return -EINVAL;
}
amdgpu_gtt_mgr_recover(&adev->mman.gtt_mgr);
table_addr = amdgpu_bo_gpu_offset(adev->gart.bo);
/* empty context1-15 */ /* FIXME start with 4G, once using 2 level pt switch to full * vm size space
*/ /* set vm size, must be a multiple of 4 */
WREG32(mmVM_CONTEXT1_PAGE_TABLE_START_ADDR, 0);
WREG32(mmVM_CONTEXT1_PAGE_TABLE_END_ADDR, adev->vm_manager.max_pfn - 1); for (i = 1; i < AMDGPU_NUM_VMID; i++) { if (i < 8)
WREG32(mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR + i,
table_addr >> 12); else
WREG32(mmVM_CONTEXT8_PAGE_TABLE_BASE_ADDR + i - 8,
table_addr >> 12);
}
r = amdgpu_irq_add_id(adev, AMDGPU_IRQ_CLIENTID_LEGACY, VISLANDS30_IV_SRCID_GFX_PAGE_INV_FAULT, &adev->gmc.vm_fault); if (r) return r;
r = amdgpu_irq_add_id(adev, AMDGPU_IRQ_CLIENTID_LEGACY, VISLANDS30_IV_SRCID_GFX_MEM_PROT_FAULT, &adev->gmc.vm_fault); if (r) return r;
/* Adjust VM size here. * Currently set to 4GB ((1 << 20) 4k pages). * Max GPUVM size for cayman and SI is 40 bits.
*/
amdgpu_vm_adjust_size(adev, 64, 9, 1, 40);
/* Set the internal MC address mask * This is the max address of the GPU's * internal address space.
*/
adev->gmc.mc_mask = 0xffffffffffULL; /* 40 bit MC */
r = dma_set_mask_and_coherent(adev->dev, DMA_BIT_MASK(40)); if (r) {
pr_warn("No suitable DMA available\n"); return r;
}
adev->need_swiotlb = drm_need_swiotlb(40);
r = gmc_v8_0_init_microcode(adev); if (r) {
DRM_ERROR("Failed to load mc firmware!\n"); return r;
}
r = gmc_v8_0_mc_init(adev); if (r) return r;
amdgpu_gmc_get_vbios_allocations(adev);
/* Memory manager */
r = amdgpu_bo_init(adev); if (r) return r;
r = gmc_v8_0_gart_init(adev); if (r) return r;
/* * number of VMs * VMID 0 is reserved for System * amdgpu graphics/compute will use VMIDs 1-7 * amdkfd will use VMIDs 8-15
*/
adev->vm_manager.first_kfd_vmid = 8;
amdgpu_vm_manager_init(adev);
/* base offset of vram pages */ if (adev->flags & AMD_IS_APU) {
u64 tmp = RREG32(mmMC_VM_FB_OFFSET);
if (amdgpu_sriov_vf(adev)) {
dev_err(adev->dev, "GPU fault detected: %d 0x%08x\n",
entry->src_id, entry->src_data[0]);
dev_err(adev->dev, " Can't decode VM fault info here on SRIOV VF\n"); return 0;
}
addr = RREG32(mmVM_CONTEXT1_PROTECTION_FAULT_ADDR);
status = RREG32(mmVM_CONTEXT1_PROTECTION_FAULT_STATUS);
mc_client = RREG32(mmVM_CONTEXT1_PROTECTION_FAULT_MCCLIENT); /* reset addr and status */
WREG32_P(mmVM_CONTEXT1_CNTL2, 1, ~1);
if (enable && (adev->cg_flags & AMD_CG_SUPPORT_MC_MGCG)) {
data = RREG32(mmMC_HUB_MISC_HUB_CG);
data |= MC_HUB_MISC_HUB_CG__ENABLE_MASK;
WREG32(mmMC_HUB_MISC_HUB_CG, data);
data = RREG32(mmMC_HUB_MISC_SIP_CG);
data |= MC_HUB_MISC_SIP_CG__ENABLE_MASK;
WREG32(mmMC_HUB_MISC_SIP_CG, data);
data = RREG32(mmMC_HUB_MISC_VM_CG);
data |= MC_HUB_MISC_VM_CG__ENABLE_MASK;
WREG32(mmMC_HUB_MISC_VM_CG, data);
data = RREG32(mmMC_XPB_CLK_GAT);
data |= MC_XPB_CLK_GAT__ENABLE_MASK;
WREG32(mmMC_XPB_CLK_GAT, data);
data = RREG32(mmATC_MISC_CG);
data |= ATC_MISC_CG__ENABLE_MASK;
WREG32(mmATC_MISC_CG, data);
data = RREG32(mmMC_CITF_MISC_WR_CG);
data |= MC_CITF_MISC_WR_CG__ENABLE_MASK;
WREG32(mmMC_CITF_MISC_WR_CG, data);
data = RREG32(mmMC_CITF_MISC_RD_CG);
data |= MC_CITF_MISC_RD_CG__ENABLE_MASK;
WREG32(mmMC_CITF_MISC_RD_CG, data);
data = RREG32(mmMC_CITF_MISC_VM_CG);
data |= MC_CITF_MISC_VM_CG__ENABLE_MASK;
WREG32(mmMC_CITF_MISC_VM_CG, data);
data = RREG32(mmVM_L2_CG);
data |= VM_L2_CG__ENABLE_MASK;
WREG32(mmVM_L2_CG, data);
} else {
data = RREG32(mmMC_HUB_MISC_HUB_CG);
data &= ~MC_HUB_MISC_HUB_CG__ENABLE_MASK;
WREG32(mmMC_HUB_MISC_HUB_CG, data);
data = RREG32(mmMC_HUB_MISC_SIP_CG);
data &= ~MC_HUB_MISC_SIP_CG__ENABLE_MASK;
WREG32(mmMC_HUB_MISC_SIP_CG, data);
data = RREG32(mmMC_HUB_MISC_VM_CG);
data &= ~MC_HUB_MISC_VM_CG__ENABLE_MASK;
WREG32(mmMC_HUB_MISC_VM_CG, data);
data = RREG32(mmMC_XPB_CLK_GAT);
data &= ~MC_XPB_CLK_GAT__ENABLE_MASK;
WREG32(mmMC_XPB_CLK_GAT, data);
data = RREG32(mmATC_MISC_CG);
data &= ~ATC_MISC_CG__ENABLE_MASK;
WREG32(mmATC_MISC_CG, data);
data = RREG32(mmMC_CITF_MISC_WR_CG);
data &= ~MC_CITF_MISC_WR_CG__ENABLE_MASK;
WREG32(mmMC_CITF_MISC_WR_CG, data);
data = RREG32(mmMC_CITF_MISC_RD_CG);
data &= ~MC_CITF_MISC_RD_CG__ENABLE_MASK;
WREG32(mmMC_CITF_MISC_RD_CG, data);
data = RREG32(mmMC_CITF_MISC_VM_CG);
data &= ~MC_CITF_MISC_VM_CG__ENABLE_MASK;
WREG32(mmMC_CITF_MISC_VM_CG, data);
data = RREG32(mmVM_L2_CG);
data &= ~VM_L2_CG__ENABLE_MASK;
WREG32(mmVM_L2_CG, data);
}
}
if (enable && (adev->cg_flags & AMD_CG_SUPPORT_MC_LS)) {
data = RREG32(mmMC_HUB_MISC_HUB_CG);
data |= MC_HUB_MISC_HUB_CG__MEM_LS_ENABLE_MASK;
WREG32(mmMC_HUB_MISC_HUB_CG, data);
data = RREG32(mmMC_HUB_MISC_SIP_CG);
data |= MC_HUB_MISC_SIP_CG__MEM_LS_ENABLE_MASK;
WREG32(mmMC_HUB_MISC_SIP_CG, data);
data = RREG32(mmMC_HUB_MISC_VM_CG);
data |= MC_HUB_MISC_VM_CG__MEM_LS_ENABLE_MASK;
WREG32(mmMC_HUB_MISC_VM_CG, data);
data = RREG32(mmMC_XPB_CLK_GAT);
data |= MC_XPB_CLK_GAT__MEM_LS_ENABLE_MASK;
WREG32(mmMC_XPB_CLK_GAT, data);
data = RREG32(mmATC_MISC_CG);
data |= ATC_MISC_CG__MEM_LS_ENABLE_MASK;
WREG32(mmATC_MISC_CG, data);
data = RREG32(mmMC_CITF_MISC_WR_CG);
data |= MC_CITF_MISC_WR_CG__MEM_LS_ENABLE_MASK;
WREG32(mmMC_CITF_MISC_WR_CG, data);
data = RREG32(mmMC_CITF_MISC_RD_CG);
data |= MC_CITF_MISC_RD_CG__MEM_LS_ENABLE_MASK;
WREG32(mmMC_CITF_MISC_RD_CG, data);
data = RREG32(mmMC_CITF_MISC_VM_CG);
data |= MC_CITF_MISC_VM_CG__MEM_LS_ENABLE_MASK;
WREG32(mmMC_CITF_MISC_VM_CG, data);
data = RREG32(mmVM_L2_CG);
data |= VM_L2_CG__MEM_LS_ENABLE_MASK;
WREG32(mmVM_L2_CG, data);
} else {
data = RREG32(mmMC_HUB_MISC_HUB_CG);
data &= ~MC_HUB_MISC_HUB_CG__MEM_LS_ENABLE_MASK;
WREG32(mmMC_HUB_MISC_HUB_CG, data);
data = RREG32(mmMC_HUB_MISC_SIP_CG);
data &= ~MC_HUB_MISC_SIP_CG__MEM_LS_ENABLE_MASK;
WREG32(mmMC_HUB_MISC_SIP_CG, data);
data = RREG32(mmMC_HUB_MISC_VM_CG);
data &= ~MC_HUB_MISC_VM_CG__MEM_LS_ENABLE_MASK;
WREG32(mmMC_HUB_MISC_VM_CG, data);
data = RREG32(mmMC_XPB_CLK_GAT);
data &= ~MC_XPB_CLK_GAT__MEM_LS_ENABLE_MASK;
WREG32(mmMC_XPB_CLK_GAT, data);
data = RREG32(mmATC_MISC_CG);
data &= ~ATC_MISC_CG__MEM_LS_ENABLE_MASK;
WREG32(mmATC_MISC_CG, data);
data = RREG32(mmMC_CITF_MISC_WR_CG);
data &= ~MC_CITF_MISC_WR_CG__MEM_LS_ENABLE_MASK;
WREG32(mmMC_CITF_MISC_WR_CG, data);
data = RREG32(mmMC_CITF_MISC_RD_CG);
data &= ~MC_CITF_MISC_RD_CG__MEM_LS_ENABLE_MASK;
WREG32(mmMC_CITF_MISC_RD_CG, data);
data = RREG32(mmMC_CITF_MISC_VM_CG);
data &= ~MC_CITF_MISC_VM_CG__MEM_LS_ENABLE_MASK;
WREG32(mmMC_CITF_MISC_VM_CG, data);
data = RREG32(mmVM_L2_CG);
data &= ~VM_L2_CG__MEM_LS_ENABLE_MASK;
WREG32(mmVM_L2_CG, data);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.