xref: /linux/drivers/gpu/drm/xe/xe_nvm.c (revision 0710dd08824a6f3b9892fc5be24acd2e4a36f178)
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_mmio.h"
11 #include "xe_nvm.h"
12 #include "xe_pcode_api.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 	struct auxiliary_device *aux = container_of(dev, struct auxiliary_device, dev);
39 	struct intel_dg_nvm_dev *nvm = container_of(aux, struct intel_dg_nvm_dev, aux_dev);
40 
41 	kfree(nvm);
42 }
43 
44 static bool xe_nvm_non_posted_erase(struct xe_device *xe)
45 {
46 	struct xe_mmio *mmio = xe_root_tile_mmio(xe);
47 
48 	switch (xe->info.platform) {
49 	case XE_CRESCENTISLAND:
50 	case XE_BATTLEMAGE:
51 		return !(xe_mmio_read32(mmio, XE_REG(GEN12_CNTL_PROTECTED_NVM_REG)) &
52 			 NVM_NON_POSTED_ERASE_CHICKEN_BIT);
53 	default:
54 		return false;
55 	}
56 }
57 
58 static bool xe_nvm_writable_override(struct xe_device *xe)
59 {
60 	struct xe_mmio *mmio = xe_root_tile_mmio(xe);
61 	bool writable_override;
62 	struct xe_reg reg;
63 	u32 test_bit, test_val;
64 
65 	switch (xe->info.platform) {
66 	case XE_CRESCENTISLAND:
67 		reg = PCODE_SCRATCH(0);
68 		test_bit = FDO_MODE;
69 		test_val = FDO_MODE;
70 		break;
71 	case XE_BATTLEMAGE:
72 		reg = HECI_FWSTS2(DG2_GSC_HECI2_BASE);
73 		test_bit = HECI_FW_STATUS_2_NVM_ACCESS_MODE;
74 		test_val = 0;
75 		break;
76 	case XE_PVC:
77 		reg = HECI_FWSTS2(PVC_GSC_HECI2_BASE);
78 		test_bit = HECI_FW_STATUS_2_NVM_ACCESS_MODE;
79 		test_val = 0;
80 		break;
81 	case XE_DG2:
82 		reg = HECI_FWSTS2(DG2_GSC_HECI2_BASE);
83 		test_bit = HECI_FW_STATUS_2_NVM_ACCESS_MODE;
84 		test_val = 0;
85 		break;
86 	case XE_DG1:
87 		reg = HECI_FWSTS2(DG1_GSC_HECI2_BASE);
88 		test_bit = HECI_FW_STATUS_2_NVM_ACCESS_MODE;
89 		test_val = 0;
90 		break;
91 	default:
92 		drm_err(&xe->drm, "Unknown platform\n");
93 		return true;
94 	}
95 
96 	writable_override = (xe_mmio_read32(mmio, reg) & test_bit) == test_val;
97 	if (writable_override)
98 		drm_info(&xe->drm, "NVM access overridden by jumper\n");
99 	return writable_override;
100 }
101 
102 static void xe_nvm_fini(void *arg)
103 {
104 	struct xe_device *xe = arg;
105 	struct intel_dg_nvm_dev *nvm = xe->nvm;
106 
107 	if (!xe->info.has_gsc_nvm)
108 		return;
109 
110 	/* No access to internal NVM from VFs */
111 	if (IS_SRIOV_VF(xe))
112 		return;
113 
114 	/* Nvm pointer should not be NULL here */
115 	if (WARN_ON(!nvm))
116 		return;
117 
118 	auxiliary_device_delete(&nvm->aux_dev);
119 	auxiliary_device_uninit(&nvm->aux_dev);
120 	xe->nvm = NULL;
121 }
122 
123 int xe_nvm_init(struct xe_device *xe)
124 {
125 	struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
126 	struct auxiliary_device *aux_dev;
127 	struct intel_dg_nvm_dev *nvm;
128 	int ret;
129 
130 	if (!xe->info.has_gsc_nvm)
131 		return 0;
132 
133 	/* No access to internal NVM from VFs */
134 	if (IS_SRIOV_VF(xe))
135 		return 0;
136 
137 	/* Nvm pointer should be NULL here */
138 	if (WARN_ON(xe->nvm))
139 		return -EFAULT;
140 
141 	nvm = kzalloc_obj(*nvm);
142 	if (!nvm)
143 		return -ENOMEM;
144 
145 	nvm->writable_override = xe_nvm_writable_override(xe);
146 	nvm->non_posted_erase = xe_nvm_non_posted_erase(xe);
147 	nvm->bar.parent = &pdev->resource[0];
148 	nvm->bar.start = GEN12_GUNIT_NVM_BASE + pdev->resource[0].start;
149 	nvm->bar.end = nvm->bar.start + GEN12_GUNIT_NVM_SIZE - 1;
150 	nvm->bar.flags = IORESOURCE_MEM;
151 	nvm->bar.desc = IORES_DESC_NONE;
152 	nvm->regions = regions;
153 
154 	nvm->bar2.parent = &pdev->resource[0];
155 	nvm->bar2.start = GEN12_DEBUG_NVM_BASE + pdev->resource[0].start;
156 	nvm->bar2.end = nvm->bar2.start + GEN12_DEBUG_NVM_SIZE - 1;
157 	nvm->bar2.flags = IORESOURCE_MEM;
158 	nvm->bar2.desc = IORES_DESC_NONE;
159 
160 	aux_dev = &nvm->aux_dev;
161 
162 	aux_dev->name = "nvm";
163 	aux_dev->id = (pci_domain_nr(pdev->bus) << 16) | pci_dev_id(pdev);
164 	aux_dev->dev.parent = &pdev->dev;
165 	aux_dev->dev.release = xe_nvm_release_dev;
166 
167 	ret = auxiliary_device_init(aux_dev);
168 	if (ret) {
169 		drm_err(&xe->drm, "xe-nvm aux init failed %d\n", ret);
170 		kfree(nvm);
171 		return ret;
172 	}
173 
174 	ret = auxiliary_device_add(aux_dev);
175 	if (ret) {
176 		drm_err(&xe->drm, "xe-nvm aux add failed %d\n", ret);
177 		auxiliary_device_uninit(aux_dev);
178 		return ret;
179 	}
180 
181 	xe->nvm = nvm;
182 	return devm_add_action_or_reset(xe->drm.dev, xe_nvm_fini, xe);
183 }
184