]> Git Repo - linux.git/blob - drivers/gpu/drm/i915/intel_huc.c
Merge remote-tracking branches 'asoc/topic/rockchip', 'asoc/topic/rt5514', 'asoc...
[linux.git] / drivers / gpu / drm / i915 / intel_huc.c
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_init() - initiate HuC firmware loading request
145  * @dev_priv: the drm_i915_private device
146  *
147  * Called early during driver load, but after GEM is initialised. The loading
148  * will continue only when driver explicitly specify firmware name and version.
149  * All other cases are considered as INTEL_UC_FIRMWARE_NONE either because HW
150  * is not capable or driver yet support it. And there will be no error message
151  * for INTEL_UC_FIRMWARE_NONE cases.
152  *
153  * The DMA-copying to HW is done later when intel_huc_load() is called.
154  */
155 void intel_huc_init(struct drm_i915_private *dev_priv)
156 {
157         struct intel_huc *huc = &dev_priv->huc;
158         struct intel_uc_fw *huc_fw = &huc->fw;
159         const char *fw_path = NULL;
160
161         huc_fw->path = NULL;
162         huc_fw->fetch_status = INTEL_UC_FIRMWARE_NONE;
163         huc_fw->load_status = INTEL_UC_FIRMWARE_NONE;
164         huc_fw->fw = INTEL_UC_FW_TYPE_HUC;
165
166         if (!HAS_HUC_UCODE(dev_priv))
167                 return;
168
169         if (IS_SKYLAKE(dev_priv)) {
170                 fw_path = I915_SKL_HUC_UCODE;
171                 huc_fw->major_ver_wanted = SKL_HUC_FW_MAJOR;
172                 huc_fw->minor_ver_wanted = SKL_HUC_FW_MINOR;
173         } else if (IS_BROXTON(dev_priv)) {
174                 fw_path = I915_BXT_HUC_UCODE;
175                 huc_fw->major_ver_wanted = BXT_HUC_FW_MAJOR;
176                 huc_fw->minor_ver_wanted = BXT_HUC_FW_MINOR;
177         } else if (IS_KABYLAKE(dev_priv)) {
178                 fw_path = I915_KBL_HUC_UCODE;
179                 huc_fw->major_ver_wanted = KBL_HUC_FW_MAJOR;
180                 huc_fw->minor_ver_wanted = KBL_HUC_FW_MINOR;
181         }
182
183         huc_fw->path = fw_path;
184         huc_fw->fetch_status = INTEL_UC_FIRMWARE_PENDING;
185
186         DRM_DEBUG_DRIVER("HuC firmware pending, path %s\n", fw_path);
187
188         WARN(huc_fw->path == NULL, "HuC present but no fw path\n");
189
190         intel_uc_fw_fetch(dev_priv, huc_fw);
191 }
192
193 /**
194  * intel_huc_load() - load HuC uCode to device
195  * @dev_priv: the drm_i915_private device
196  *
197  * Called from guc_setup() during driver loading and also after a GPU reset.
198  * Be note that HuC loading must be done before GuC loading.
199  *
200  * The firmware image should have already been fetched into memory by the
201  * earlier call to intel_huc_init(), so here we need only check that
202  * is succeeded, and then transfer the image to the h/w.
203  *
204  * Return:      non-zero code on error
205  */
206 int intel_huc_load(struct drm_i915_private *dev_priv)
207 {
208         struct intel_uc_fw *huc_fw = &dev_priv->huc.fw;
209         int err;
210
211         if (huc_fw->fetch_status == INTEL_UC_FIRMWARE_NONE)
212                 return 0;
213
214         DRM_DEBUG_DRIVER("%s fw status: fetch %s, load %s\n",
215                 huc_fw->path,
216                 intel_uc_fw_status_repr(huc_fw->fetch_status),
217                 intel_uc_fw_status_repr(huc_fw->load_status));
218
219         if (huc_fw->fetch_status == INTEL_UC_FIRMWARE_SUCCESS &&
220             huc_fw->load_status == INTEL_UC_FIRMWARE_FAIL)
221                 return -ENOEXEC;
222
223         huc_fw->load_status = INTEL_UC_FIRMWARE_PENDING;
224
225         switch (huc_fw->fetch_status) {
226         case INTEL_UC_FIRMWARE_FAIL:
227                 /* something went wrong :( */
228                 err = -EIO;
229                 goto fail;
230
231         case INTEL_UC_FIRMWARE_NONE:
232         case INTEL_UC_FIRMWARE_PENDING:
233         default:
234                 /* "can't happen" */
235                 WARN_ONCE(1, "HuC fw %s invalid fetch_status %s [%d]\n",
236                         huc_fw->path,
237                         intel_uc_fw_status_repr(huc_fw->fetch_status),
238                         huc_fw->fetch_status);
239                 err = -ENXIO;
240                 goto fail;
241
242         case INTEL_UC_FIRMWARE_SUCCESS:
243                 break;
244         }
245
246         err = huc_ucode_xfer(dev_priv);
247         if (err)
248                 goto fail;
249
250         huc_fw->load_status = INTEL_UC_FIRMWARE_SUCCESS;
251
252         DRM_DEBUG_DRIVER("%s fw status: fetch %s, load %s\n",
253                 huc_fw->path,
254                 intel_uc_fw_status_repr(huc_fw->fetch_status),
255                 intel_uc_fw_status_repr(huc_fw->load_status));
256
257         return 0;
258
259 fail:
260         if (huc_fw->load_status == INTEL_UC_FIRMWARE_PENDING)
261                 huc_fw->load_status = INTEL_UC_FIRMWARE_FAIL;
262
263         DRM_ERROR("Failed to complete HuC uCode load with ret %d\n", err);
264
265         return err;
266 }
267
268 /**
269  * intel_huc_fini() - clean up resources allocated for HuC
270  * @dev_priv: the drm_i915_private device
271  *
272  * Cleans up by releasing the huc firmware GEM obj.
273  */
274 void intel_huc_fini(struct drm_i915_private *dev_priv)
275 {
276         struct intel_uc_fw *huc_fw = &dev_priv->huc.fw;
277
278         mutex_lock(&dev_priv->drm.struct_mutex);
279         if (huc_fw->obj)
280                 i915_gem_object_put(huc_fw->obj);
281         huc_fw->obj = NULL;
282         mutex_unlock(&dev_priv->drm.struct_mutex);
283
284         huc_fw->fetch_status = INTEL_UC_FIRMWARE_NONE;
285 }
286
287 /**
288  * intel_guc_auth_huc() - authenticate ucode
289  * @dev_priv: the drm_i915_device
290  *
291  * Triggers a HuC fw authentication request to the GuC via intel_guc_action_
292  * authenticate_huc interface.
293  */
294 void intel_guc_auth_huc(struct drm_i915_private *dev_priv)
295 {
296         struct intel_guc *guc = &dev_priv->guc;
297         struct intel_huc *huc = &dev_priv->huc;
298         struct i915_vma *vma;
299         int ret;
300         u32 data[2];
301
302         if (huc->fw.load_status != INTEL_UC_FIRMWARE_SUCCESS)
303                 return;
304
305         vma = i915_gem_object_ggtt_pin(huc->fw.obj, NULL, 0, 0,
306                                 PIN_OFFSET_BIAS | GUC_WOPCM_TOP);
307         if (IS_ERR(vma)) {
308                 DRM_ERROR("failed to pin huc fw object %d\n",
309                                 (int)PTR_ERR(vma));
310                 return;
311         }
312
313         /* Specify auth action and where public signature is. */
314         data[0] = INTEL_GUC_ACTION_AUTHENTICATE_HUC;
315         data[1] = guc_ggtt_offset(vma) + huc->fw.rsa_offset;
316
317         ret = intel_guc_send(guc, data, ARRAY_SIZE(data));
318         if (ret) {
319                 DRM_ERROR("HuC: GuC did not ack Auth request %d\n", ret);
320                 goto out;
321         }
322
323         /* Check authentication status, it should be done by now */
324         ret = intel_wait_for_register(dev_priv,
325                                 HUC_STATUS2,
326                                 HUC_FW_VERIFIED,
327                                 HUC_FW_VERIFIED,
328                                 50);
329
330         if (ret) {
331                 DRM_ERROR("HuC: Authentication failed %d\n", ret);
332                 goto out;
333         }
334
335 out:
336         i915_vma_unpin(vma);
337 }
338
This page took 0.05291 seconds and 4 git commands to generate.