1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright(c) 2019-2025, Intel Corporation. All rights reserved. 4 */ 5 6 #include <linux/intel_dg_nvm_aux.h> 7 #include <linux/pci.h> 8 9 #include "xe_device.h" 10 #include "xe_device_types.h" 11 #include "xe_mmio.h" 12 #include "xe_nvm.h" 13 #include "regs/xe_gsc_regs.h" 14 #include "xe_sriov.h" 15 16 #define GEN12_GUNIT_NVM_BASE 0x00102040 17 #define GEN12_DEBUG_NVM_BASE 0x00101018 18 19 #define GEN12_CNTL_PROTECTED_NVM_REG 0x0010100C 20 21 #define GEN12_GUNIT_NVM_SIZE 0x80 22 #define GEN12_DEBUG_NVM_SIZE 0x4 23 24 #define NVM_NON_POSTED_ERASE_CHICKEN_BIT BIT(13) 25 26 #define HECI_FW_STATUS_2_NVM_ACCESS_MODE BIT(3) 27 28 static const struct intel_dg_nvm_region regions[INTEL_DG_NVM_REGIONS] = { 29 [0] = { .name = "DESCRIPTOR", }, 30 [2] = { .name = "GSC", }, 31 [9] = { .name = "PADDING", }, 32 [11] = { .name = "OptionROM", }, 33 [12] = { .name = "DAM", }, 34 }; 35 36 static void xe_nvm_release_dev(struct device *dev) 37 { 38 } 39 40 static bool xe_nvm_non_posted_erase(struct xe_device *xe) 41 { 42 struct xe_gt *gt = xe_root_mmio_gt(xe); 43 44 if (xe->info.platform != XE_BATTLEMAGE) 45 return false; 46 return !(xe_mmio_read32(>->mmio, XE_REG(GEN12_CNTL_PROTECTED_NVM_REG)) & 47 NVM_NON_POSTED_ERASE_CHICKEN_BIT); 48 } 49 50 static bool xe_nvm_writable_override(struct xe_device *xe) 51 { 52 struct xe_gt *gt = xe_root_mmio_gt(xe); 53 bool writable_override; 54 resource_size_t base; 55 56 switch (xe->info.platform) { 57 case XE_BATTLEMAGE: 58 base = DG2_GSC_HECI2_BASE; 59 break; 60 case XE_PVC: 61 base = PVC_GSC_HECI2_BASE; 62 break; 63 case XE_DG2: 64 base = DG2_GSC_HECI2_BASE; 65 break; 66 case XE_DG1: 67 base = DG1_GSC_HECI2_BASE; 68 break; 69 default: 70 drm_err(&xe->drm, "Unknown platform\n"); 71 return true; 72 } 73 74 writable_override = 75 !(xe_mmio_read32(>->mmio, HECI_FWSTS2(base)) & 76 HECI_FW_STATUS_2_NVM_ACCESS_MODE); 77 if (writable_override) 78 drm_info(&xe->drm, "NVM access overridden by jumper\n"); 79 return writable_override; 80 } 81 82 int xe_nvm_init(struct xe_device *xe) 83 { 84 struct pci_dev *pdev = to_pci_dev(xe->drm.dev); 85 struct auxiliary_device *aux_dev; 86 struct intel_dg_nvm_dev *nvm; 87 int ret; 88 89 if (!xe->info.has_gsc_nvm) 90 return 0; 91 92 /* No access to internal NVM from VFs */ 93 if (IS_SRIOV_VF(xe)) 94 return 0; 95 96 /* Nvm pointer should be NULL here */ 97 if (WARN_ON(xe->nvm)) 98 return -EFAULT; 99 100 xe->nvm = kzalloc(sizeof(*nvm), GFP_KERNEL); 101 if (!xe->nvm) 102 return -ENOMEM; 103 104 nvm = xe->nvm; 105 106 nvm->writable_override = xe_nvm_writable_override(xe); 107 nvm->non_posted_erase = xe_nvm_non_posted_erase(xe); 108 nvm->bar.parent = &pdev->resource[0]; 109 nvm->bar.start = GEN12_GUNIT_NVM_BASE + pdev->resource[0].start; 110 nvm->bar.end = nvm->bar.start + GEN12_GUNIT_NVM_SIZE - 1; 111 nvm->bar.flags = IORESOURCE_MEM; 112 nvm->bar.desc = IORES_DESC_NONE; 113 nvm->regions = regions; 114 115 nvm->bar2.parent = &pdev->resource[0]; 116 nvm->bar2.start = GEN12_DEBUG_NVM_BASE + pdev->resource[0].start; 117 nvm->bar2.end = nvm->bar2.start + GEN12_DEBUG_NVM_SIZE - 1; 118 nvm->bar2.flags = IORESOURCE_MEM; 119 nvm->bar2.desc = IORES_DESC_NONE; 120 121 aux_dev = &nvm->aux_dev; 122 123 aux_dev->name = "nvm"; 124 aux_dev->id = (pci_domain_nr(pdev->bus) << 16) | pci_dev_id(pdev); 125 aux_dev->dev.parent = &pdev->dev; 126 aux_dev->dev.release = xe_nvm_release_dev; 127 128 ret = auxiliary_device_init(aux_dev); 129 if (ret) { 130 drm_err(&xe->drm, "xe-nvm aux init failed %d\n", ret); 131 goto err; 132 } 133 134 ret = auxiliary_device_add(aux_dev); 135 if (ret) { 136 drm_err(&xe->drm, "xe-nvm aux add failed %d\n", ret); 137 auxiliary_device_uninit(aux_dev); 138 goto err; 139 } 140 return 0; 141 142 err: 143 kfree(nvm); 144 xe->nvm = NULL; 145 return ret; 146 } 147 148 void xe_nvm_fini(struct xe_device *xe) 149 { 150 struct intel_dg_nvm_dev *nvm = xe->nvm; 151 152 if (!xe->info.has_gsc_nvm) 153 return; 154 155 /* No access to internal NVM from VFs */ 156 if (IS_SRIOV_VF(xe)) 157 return; 158 159 /* Nvm pointer should not be NULL here */ 160 if (WARN_ON(!nvm)) 161 return; 162 163 auxiliary_device_delete(&nvm->aux_dev); 164 auxiliary_device_uninit(&nvm->aux_dev); 165 kfree(nvm); 166 xe->nvm = NULL; 167 } 168