xref: /dragonfly/sys/dev/drm/i915/intel_huc.c (revision b9a6fe08)
1 /*
2  * Copyright © 2016-2017 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  *
23  */
24 #include <linux/firmware.h>
25 #include "i915_drv.h"
26 #include "intel_uc.h"
27 
28 /**
29  * DOC: HuC Firmware
30  *
31  * Motivation:
32  * GEN9 introduces a new dedicated firmware for usage in media HEVC (High
33  * Efficiency Video Coding) operations. Userspace can use the firmware
34  * capabilities by adding HuC specific commands to batch buffers.
35  *
36  * Implementation:
37  * The same firmware loader is used as the GuC. However, the actual
38  * loading to HW is deferred until GEM initialization is done.
39  *
40  * Note that HuC firmware loading must be done before GuC loading.
41  */
42 
43 #define BXT_HUC_FW_MAJOR 01
44 #define BXT_HUC_FW_MINOR 07
45 #define BXT_BLD_NUM 1398
46 
47 #define SKL_HUC_FW_MAJOR 01
48 #define SKL_HUC_FW_MINOR 07
49 #define SKL_BLD_NUM 1398
50 
51 #define KBL_HUC_FW_MAJOR 02
52 #define KBL_HUC_FW_MINOR 00
53 #define KBL_BLD_NUM 1810
54 
55 #define HUC_FW_PATH(platform, major, minor, bld_num) \
56 	"i915/" __stringify(platform) "_huc_ver" __stringify(major) "_" \
57 	__stringify(minor) "_" __stringify(bld_num) ".bin"
58 
59 #define I915_SKL_HUC_UCODE HUC_FW_PATH(skl, SKL_HUC_FW_MAJOR, \
60 	SKL_HUC_FW_MINOR, SKL_BLD_NUM)
61 MODULE_FIRMWARE(I915_SKL_HUC_UCODE);
62 
63 #define I915_BXT_HUC_UCODE HUC_FW_PATH(bxt, BXT_HUC_FW_MAJOR, \
64 	BXT_HUC_FW_MINOR, BXT_BLD_NUM)
65 MODULE_FIRMWARE(I915_BXT_HUC_UCODE);
66 
67 #define I915_KBL_HUC_UCODE HUC_FW_PATH(kbl, KBL_HUC_FW_MAJOR, \
68 	KBL_HUC_FW_MINOR, KBL_BLD_NUM)
69 MODULE_FIRMWARE(I915_KBL_HUC_UCODE);
70 
71 /**
72  * huc_ucode_xfer() - DMA's the firmware
73  * @dev_priv: the drm_i915_private device
74  *
75  * Transfer the firmware image to RAM for execution by the microcontroller.
76  *
77  * Return: 0 on success, non-zero on failure
78  */
79 static int huc_ucode_xfer(struct drm_i915_private *dev_priv)
80 {
81 	struct intel_uc_fw *huc_fw = &dev_priv->huc.fw;
82 	struct i915_vma *vma;
83 	unsigned long offset = 0;
84 	u32 size;
85 	int ret;
86 
87 	ret = i915_gem_object_set_to_gtt_domain(huc_fw->obj, false);
88 	if (ret) {
89 		DRM_DEBUG_DRIVER("set-domain failed %d\n", ret);
90 		return ret;
91 	}
92 
93 	vma = i915_gem_object_ggtt_pin(huc_fw->obj, NULL, 0, 0,
94 				PIN_OFFSET_BIAS | GUC_WOPCM_TOP);
95 	if (IS_ERR(vma)) {
96 		DRM_DEBUG_DRIVER("pin failed %d\n", (int)PTR_ERR(vma));
97 		return PTR_ERR(vma);
98 	}
99 
100 	intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
101 
102 	/* init WOPCM */
103 	I915_WRITE(GUC_WOPCM_SIZE, intel_guc_wopcm_size(dev_priv));
104 	I915_WRITE(DMA_GUC_WOPCM_OFFSET, GUC_WOPCM_OFFSET_VALUE |
105 			HUC_LOADING_AGENT_GUC);
106 
107 	/* Set the source address for the uCode */
108 	offset = guc_ggtt_offset(vma) + huc_fw->header_offset;
109 	I915_WRITE(DMA_ADDR_0_LOW, lower_32_bits(offset));
110 	I915_WRITE(DMA_ADDR_0_HIGH, upper_32_bits(offset) & 0xFFFF);
111 
112 	/* Hardware doesn't look at destination address for HuC. Set it to 0,
113 	 * but still program the correct address space.
114 	 */
115 	I915_WRITE(DMA_ADDR_1_LOW, 0);
116 	I915_WRITE(DMA_ADDR_1_HIGH, DMA_ADDRESS_SPACE_WOPCM);
117 
118 	size = huc_fw->header_size + huc_fw->ucode_size;
119 	I915_WRITE(DMA_COPY_SIZE, size);
120 
121 	/* Start the DMA */
122 	I915_WRITE(DMA_CTRL, _MASKED_BIT_ENABLE(HUC_UKERNEL | START_DMA));
123 
124 	/* Wait for DMA to finish */
125 	ret = wait_for((I915_READ(DMA_CTRL) & START_DMA) == 0, 100);
126 
127 	DRM_DEBUG_DRIVER("HuC DMA transfer wait over with ret %d\n", ret);
128 
129 	/* Disable the bits once DMA is over */
130 	I915_WRITE(DMA_CTRL, _MASKED_BIT_DISABLE(HUC_UKERNEL));
131 
132 	intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
133 
134 	/*
135 	 * We keep the object pages for reuse during resume. But we can unpin it
136 	 * now that DMA has completed, so it doesn't continue to take up space.
137 	 */
138 	i915_vma_unpin(vma);
139 
140 	return ret;
141 }
142 
143 /**
144  * intel_huc_select_fw() - selects HuC firmware for loading
145  * @huc:	intel_huc struct
146  */
147 void intel_huc_select_fw(struct intel_huc *huc)
148 {
149 	struct drm_i915_private *dev_priv = huc_to_i915(huc);
150 
151 	huc->fw.path = NULL;
152 	huc->fw.fetch_status = INTEL_UC_FIRMWARE_NONE;
153 	huc->fw.load_status = INTEL_UC_FIRMWARE_NONE;
154 	huc->fw.type = INTEL_UC_FW_TYPE_HUC;
155 
156 	if (i915.huc_firmware_path) {
157 		huc->fw.path = i915.huc_firmware_path;
158 		huc->fw.major_ver_wanted = 0;
159 		huc->fw.minor_ver_wanted = 0;
160 	} else if (IS_SKYLAKE(dev_priv)) {
161 		huc->fw.path = I915_SKL_HUC_UCODE;
162 		huc->fw.major_ver_wanted = SKL_HUC_FW_MAJOR;
163 		huc->fw.minor_ver_wanted = SKL_HUC_FW_MINOR;
164 	} else if (IS_BROXTON(dev_priv)) {
165 		huc->fw.path = I915_BXT_HUC_UCODE;
166 		huc->fw.major_ver_wanted = BXT_HUC_FW_MAJOR;
167 		huc->fw.minor_ver_wanted = BXT_HUC_FW_MINOR;
168 	} else if (IS_KABYLAKE(dev_priv)) {
169 		huc->fw.path = I915_KBL_HUC_UCODE;
170 		huc->fw.major_ver_wanted = KBL_HUC_FW_MAJOR;
171 		huc->fw.minor_ver_wanted = KBL_HUC_FW_MINOR;
172 	} else {
173 		DRM_ERROR("No HuC firmware known for platform with HuC!\n");
174 		return;
175 	}
176 }
177 
178 /**
179  * intel_huc_init_hw() - load HuC uCode to device
180  * @huc: intel_huc structure
181  *
182  * Called from guc_setup() during driver loading and also after a GPU reset.
183  * Be note that HuC loading must be done before GuC loading.
184  *
185  * The firmware image should have already been fetched into memory by the
186  * earlier call to intel_huc_init(), so here we need only check that
187  * is succeeded, and then transfer the image to the h/w.
188  *
189  * Return:	non-zero code on error
190  */
191 int intel_huc_init_hw(struct intel_huc *huc)
192 {
193 	struct drm_i915_private *dev_priv = huc_to_i915(huc);
194 	int err;
195 
196 	if (huc->fw.fetch_status == INTEL_UC_FIRMWARE_NONE)
197 		return 0;
198 
199 	DRM_DEBUG_DRIVER("%s fw status: fetch %s, load %s\n",
200 		huc->fw.path,
201 		intel_uc_fw_status_repr(huc->fw.fetch_status),
202 		intel_uc_fw_status_repr(huc->fw.load_status));
203 
204 	if (huc->fw.fetch_status == INTEL_UC_FIRMWARE_SUCCESS &&
205 	    huc->fw.load_status == INTEL_UC_FIRMWARE_FAIL)
206 		return -ENOEXEC;
207 
208 	huc->fw.load_status = INTEL_UC_FIRMWARE_PENDING;
209 
210 	switch (huc->fw.fetch_status) {
211 	case INTEL_UC_FIRMWARE_FAIL:
212 		/* something went wrong :( */
213 		err = -EIO;
214 		goto fail;
215 
216 	case INTEL_UC_FIRMWARE_NONE:
217 	case INTEL_UC_FIRMWARE_PENDING:
218 	default:
219 		/* "can't happen" */
220 		WARN_ONCE(1, "HuC fw %s invalid fetch_status %s [%d]\n",
221 			huc->fw.path,
222 			intel_uc_fw_status_repr(huc->fw.fetch_status),
223 			huc->fw.fetch_status);
224 		err = -ENXIO;
225 		goto fail;
226 
227 	case INTEL_UC_FIRMWARE_SUCCESS:
228 		break;
229 	}
230 
231 	err = huc_ucode_xfer(dev_priv);
232 	if (err)
233 		goto fail;
234 
235 	huc->fw.load_status = INTEL_UC_FIRMWARE_SUCCESS;
236 
237 	DRM_DEBUG_DRIVER("%s fw status: fetch %s, load %s\n",
238 		huc->fw.path,
239 		intel_uc_fw_status_repr(huc->fw.fetch_status),
240 		intel_uc_fw_status_repr(huc->fw.load_status));
241 
242 	return 0;
243 
244 fail:
245 	if (huc->fw.load_status == INTEL_UC_FIRMWARE_PENDING)
246 		huc->fw.load_status = INTEL_UC_FIRMWARE_FAIL;
247 
248 	DRM_ERROR("Failed to complete HuC uCode load with ret %d\n", err);
249 
250 	return err;
251 }
252 
253 /**
254  * intel_guc_auth_huc() - authenticate ucode
255  * @dev_priv: the drm_i915_device
256  *
257  * Triggers a HuC fw authentication request to the GuC via intel_guc_action_
258  * authenticate_huc interface.
259  */
260 void intel_guc_auth_huc(struct drm_i915_private *dev_priv)
261 {
262 	struct intel_guc *guc = &dev_priv->guc;
263 	struct intel_huc *huc = &dev_priv->huc;
264 	struct i915_vma *vma;
265 	int ret;
266 	u32 data[2];
267 
268 	if (huc->fw.load_status != INTEL_UC_FIRMWARE_SUCCESS)
269 		return;
270 
271 	vma = i915_gem_object_ggtt_pin(huc->fw.obj, NULL, 0, 0,
272 				PIN_OFFSET_BIAS | GUC_WOPCM_TOP);
273 	if (IS_ERR(vma)) {
274 		DRM_ERROR("failed to pin huc fw object %d\n",
275 				(int)PTR_ERR(vma));
276 		return;
277 	}
278 
279 	/* Specify auth action and where public signature is. */
280 	data[0] = INTEL_GUC_ACTION_AUTHENTICATE_HUC;
281 	data[1] = guc_ggtt_offset(vma) + huc->fw.rsa_offset;
282 
283 	ret = intel_guc_send(guc, data, ARRAY_SIZE(data));
284 	if (ret) {
285 		DRM_ERROR("HuC: GuC did not ack Auth request %d\n", ret);
286 		goto out;
287 	}
288 
289 	/* Check authentication status, it should be done by now */
290 	ret = intel_wait_for_register(dev_priv,
291 				HUC_STATUS2,
292 				HUC_FW_VERIFIED,
293 				HUC_FW_VERIFIED,
294 				50);
295 
296 	if (ret) {
297 		DRM_ERROR("HuC: Authentication failed %d\n", ret);
298 		goto out;
299 	}
300 
301 out:
302 	i915_vma_unpin(vma);
303 }
304 
305