// SPDX-License-Identifier: MIT /* * Copyright(c) 2019-2025, Intel Corporation. All rights reserved. */ #include #include #include "xe_device.h" #include "xe_device_types.h" #include "xe_mmio.h" #include "xe_nvm.h" #include "regs/xe_gsc_regs.h" #include "xe_sriov.h" #define GEN12_GUNIT_NVM_BASE 0x00102040 #define GEN12_DEBUG_NVM_BASE 0x00101018 #define GEN12_CNTL_PROTECTED_NVM_REG 0x0010100C #define GEN12_GUNIT_NVM_SIZE 0x80 #define GEN12_DEBUG_NVM_SIZE 0x4 #define NVM_NON_POSTED_ERASE_CHICKEN_BIT BIT(13) #define HECI_FW_STATUS_2_NVM_ACCESS_MODE BIT(3) static const struct intel_dg_nvm_region regions[INTEL_DG_NVM_REGIONS] = { [0] = { .name = "DESCRIPTOR", }, [2] = { .name = "GSC", }, [9] = { .name = "PADDING", }, [11] = { .name = "OptionROM", }, [12] = { .name = "DAM", }, }; static void xe_nvm_release_dev(struct device *dev) { } static bool xe_nvm_non_posted_erase(struct xe_device *xe) { struct xe_gt *gt = xe_root_mmio_gt(xe); if (xe->info.platform != XE_BATTLEMAGE) return false; return !(xe_mmio_read32(>->mmio, XE_REG(GEN12_CNTL_PROTECTED_NVM_REG)) & NVM_NON_POSTED_ERASE_CHICKEN_BIT); } static bool xe_nvm_writable_override(struct xe_device *xe) { struct xe_gt *gt = xe_root_mmio_gt(xe); bool writable_override; resource_size_t base; switch (xe->info.platform) { case XE_BATTLEMAGE: base = DG2_GSC_HECI2_BASE; break; case XE_PVC: base = PVC_GSC_HECI2_BASE; break; case XE_DG2: base = DG2_GSC_HECI2_BASE; break; case XE_DG1: base = DG1_GSC_HECI2_BASE; break; default: drm_err(&xe->drm, "Unknown platform\n"); return true; } writable_override = !(xe_mmio_read32(>->mmio, HECI_FWSTS2(base)) & HECI_FW_STATUS_2_NVM_ACCESS_MODE); if (writable_override) drm_info(&xe->drm, "NVM access overridden by jumper\n"); return writable_override; } int xe_nvm_init(struct xe_device *xe) { struct pci_dev *pdev = to_pci_dev(xe->drm.dev); struct auxiliary_device *aux_dev; struct intel_dg_nvm_dev *nvm; int ret; if (!xe->info.has_gsc_nvm) return 0; /* No access to internal NVM from VFs */ if (IS_SRIOV_VF(xe)) return 0; /* Nvm pointer should be NULL here */ if (WARN_ON(xe->nvm)) return -EFAULT; xe->nvm = kzalloc(sizeof(*nvm), GFP_KERNEL); if (!xe->nvm) return -ENOMEM; nvm = xe->nvm; nvm->writable_override = xe_nvm_writable_override(xe); nvm->non_posted_erase = xe_nvm_non_posted_erase(xe); nvm->bar.parent = &pdev->resource[0]; nvm->bar.start = GEN12_GUNIT_NVM_BASE + pdev->resource[0].start; nvm->bar.end = nvm->bar.start + GEN12_GUNIT_NVM_SIZE - 1; nvm->bar.flags = IORESOURCE_MEM; nvm->bar.desc = IORES_DESC_NONE; nvm->regions = regions; nvm->bar2.parent = &pdev->resource[0]; nvm->bar2.start = GEN12_DEBUG_NVM_BASE + pdev->resource[0].start; nvm->bar2.end = nvm->bar2.start + GEN12_DEBUG_NVM_SIZE - 1; nvm->bar2.flags = IORESOURCE_MEM; nvm->bar2.desc = IORES_DESC_NONE; aux_dev = &nvm->aux_dev; aux_dev->name = "nvm"; aux_dev->id = (pci_domain_nr(pdev->bus) << 16) | pci_dev_id(pdev); aux_dev->dev.parent = &pdev->dev; aux_dev->dev.release = xe_nvm_release_dev; ret = auxiliary_device_init(aux_dev); if (ret) { drm_err(&xe->drm, "xe-nvm aux init failed %d\n", ret); goto err; } ret = auxiliary_device_add(aux_dev); if (ret) { drm_err(&xe->drm, "xe-nvm aux add failed %d\n", ret); auxiliary_device_uninit(aux_dev); goto err; } return 0; err: kfree(nvm); xe->nvm = NULL; return ret; } void xe_nvm_fini(struct xe_device *xe) { struct intel_dg_nvm_dev *nvm = xe->nvm; if (!xe->info.has_gsc_nvm) return; /* No access to internal NVM from VFs */ if (IS_SRIOV_VF(xe)) return; /* Nvm pointer should not be NULL here */ if (WARN_ON(!nvm)) return; auxiliary_device_delete(&nvm->aux_dev); auxiliary_device_uninit(&nvm->aux_dev); kfree(nvm); xe->nvm = NULL; }