From: Alex Dai <yu.dai@xxxxxxxxx> Add GuC firmware loader. It uses the unified firmware loader to fetch firmware blob first, then load to hw in driver main thread. Issue: VIZ-4884 Signed-off-by: Alex Dai <yu.dai@xxxxxxxxx> --- drivers/gpu/drm/i915/Makefile | 3 +- drivers/gpu/drm/i915/i915_dma.c | 6 + drivers/gpu/drm/i915/i915_drv.h | 7 + drivers/gpu/drm/i915/i915_gem_stolen.c | 10 + drivers/gpu/drm/i915/i915_reg.h | 4 +- drivers/gpu/drm/i915/intel_guc.h | 103 ++++++++++ drivers/gpu/drm/i915/intel_guc_loader.c | 348 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_uc_loader.c | 3 + drivers/gpu/drm/i915/intel_uc_loader.h | 4 + 9 files changed, 486 insertions(+), 2 deletions(-) create mode 100644 drivers/gpu/drm/i915/intel_guc.h create mode 100644 drivers/gpu/drm/i915/intel_guc_loader.c diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 1b027c7..6188302 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -40,7 +40,8 @@ i915-y += i915_cmd_parser.o \ intel_uncore.o # ancilliary microcontroller support -i915-y += intel_uc_loader.o +i915-y += intel_uc_loader.o \ + intel_guc_loader.o # autogenerated null render state i915-y += intel_renderstate_gen6.o \ diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index e44116f..5d50b5b 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -465,6 +465,7 @@ static int i915_load_modeset_init(struct drm_device *dev) cleanup_gem: mutex_lock(&dev->struct_mutex); + intel_guc_ucode_fini(dev); i915_gem_cleanup_ringbuffer(dev); i915_gem_context_fini(dev); mutex_unlock(&dev->struct_mutex); @@ -861,6 +862,10 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) intel_uncore_init(dev); + intel_wopcm_init(dev); + + intel_guc_ucode_init(dev); + ret = i915_gem_gtt_init(dev); if (ret) goto out_regs; @@ -1108,6 +1113,7 @@ int i915_driver_unload(struct drm_device *dev) flush_workqueue(dev_priv->wq); mutex_lock(&dev->struct_mutex); + intel_guc_ucode_fini(dev); i915_gem_cleanup_ringbuffer(dev); i915_gem_context_fini(dev); mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6e8d106..235fc08 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -50,6 +50,7 @@ #include <linux/intel-iommu.h> #include <linux/kref.h> #include <linux/pm_qos.h> +#include "intel_guc.h" /* General customization: */ @@ -1581,6 +1582,8 @@ struct drm_i915_private { struct intel_gmbus gmbus[GMBUS_NUM_PINS]; + struct intel_guc guc; + /** gmbus_mutex protects against concurrent usage of the single hw gmbus * controller on different i2c buses. */ struct mutex gmbus_mutex; @@ -2430,6 +2433,9 @@ struct drm_i915_cmd_table { #define HAS_RC6(dev) (INTEL_INFO(dev)->gen >= 6) #define HAS_RC6p(dev) (INTEL_INFO(dev)->gen == 6 || IS_IVYBRIDGE(dev)) +#define HAS_GUC_UCODE(dev) (IS_GEN9(dev)) +#define HAS_GUC_SCHED(dev) (IS_GEN9(dev)) + #define INTEL_PCH_DEVICE_ID_MASK 0xff00 #define INTEL_PCH_IBX_DEVICE_ID_TYPE 0x3b00 #define INTEL_PCH_CPT_DEVICE_ID_TYPE 0x1c00 @@ -3008,6 +3014,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev, u32 stolen_offset, u32 gtt_offset, u32 size); +void intel_wopcm_init(struct drm_device *dev); /* i915_gem_shrinker.c */ unsigned long i915_gem_shrink(struct drm_i915_private *dev_priv, diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index 348ed5a..fbf7667 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -551,3 +551,13 @@ err_out: drm_gem_object_unreference(&obj->base); return NULL; } + +void intel_wopcm_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (HAS_GUC_UCODE(dev)) { + I915_WRITE(GUC_WOPCM_SIZE, GUC_WOPCM_SIZE_VALUE); + I915_WRITE(DMA_GUC_WOPCM_OFFSET, GUC_WOPCM_OFFSET); + } +} diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index d47afbc..f7c00dc 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6693,7 +6693,9 @@ enum skl_disp_power_wells { #define GEN9_PGCTL_SSB_EU311_ACK (1 << 14) #define GEN7_MISCCPCTL (0x9424) -#define GEN7_DOP_CLOCK_GATE_ENABLE (1<<0) +#define GEN7_DOP_CLOCK_GATE_ENABLE (1<<0) +#define GEN8_DOP_CLOCK_GATE_CFCLK_ENABLE (1<<2) +#define GEN8_DOP_CLOCK_GATE_GUC_ENABLE (1<<4) /* IVYBRIDGE DPF */ #define GEN7_L3CDERRST1 0xB008 /* L3CD Error Status 1 */ diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h new file mode 100644 index 0000000..4fafcec --- /dev/null +++ b/drivers/gpu/drm/i915/intel_guc.h @@ -0,0 +1,103 @@ +/* + * Copyright © 2014 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + */ +#ifndef _INTEL_GUC_H_ +#define _INTEL_GUC_H_ + +#include "intel_guc_api.h" +#include "intel_uc_loader.h" + +struct intel_guc { + struct intel_uc_fw guc_fw; +}; + +#define GUC_STATUS 0xc000 +#define GS_BOOTROM_SHIFT 1 +#define GS_BOOTROM_MASK (0x7F << GS_BOOTROM_SHIFT) +#define GS_BOOTROM_RSA_FAILED (0x50 << GS_BOOTROM_SHIFT) +#define GS_UKERNEL_SHIFT 8 +#define GS_UKERNEL_MASK (0xFF << GS_UKERNEL_SHIFT) +#define GS_UKERNEL_LAPIC_DONE (0x30 << GS_UKERNEL_SHIFT) +#define GS_UKERNEL_DPC_ERROR (0x60 << GS_UKERNEL_SHIFT) +#define GS_UKERNEL_READY (0xF0 << GS_UKERNEL_SHIFT) +#define GS_MIA_SHIFT 16 +#define GS_MIA_MASK (0x7 << GS_MIA_SHIFT) + +#define GUC_WOPCM_SIZE 0xc050 +#define GUC_WOPCM_SIZE_VALUE (0x80 << 12) /* 512KB */ +#define GUC_WOPCM_OFFSET 0x80000 /* 512KB */ +#define SOFT_SCRATCH(n) (0xc180 + ((n) * 4)) + +#define UOS_CSS_HEADER_OFFSET 0 +#define UOS_CSS_HEADER_SIZE 0x80 +#define UOS_VER_MINOR_OFFSET 0x44 +#define UOS_VER_MAJOR_OFFSET 0x46 +#define UOS_RSA_SIG_OFFSET 0x80 +#define UOS_RSA_SIG_SIZE 0x100 +#define UOS_CSS_SIGNING_SIZE 0x204 +#define UOS_UCODE_OFFSET (UOS_CSS_HEADER_SIZE + UOS_CSS_SIGNING_SIZE) + +#define UOS_RSA_SCRATCH_0 0xc200 +#define DMA_ADDR_0_LOW 0xc300 +#define DMA_ADDR_0_HIGH 0xc304 +#define DMA_ADDR_1_LOW 0xc308 +#define DMA_ADDR_1_HIGH 0xc30c +#define DMA_ADDRESS_SPACE_WOPCM (7 << 16) +#define DMA_ADDRESS_SPACE_GTT (8 << 16) +#define DMA_COPY_SIZE 0xc310 +#define DMA_CTRL 0xc314 +#define UOS_MOVE (1<<4) +#define START_DMA (1<<0) +#define DMA_GUC_WOPCM_OFFSET 0xc340 + +#define GEN8_GT_PM_CONFIG 0x138140 +#define GEN9_GT_PM_CONFIG 0x13816c +#define GEN8_GT_DOORBELL_ENABLE (1<<0) + +#define GEN8_GTCR 0x4274 +#define GEN8_GTCR_INVALIDATE (1<<0) + +#define GUC_ARAT_C6DIS 0xA178 + +#define GUC_SHIM_CONTROL (0xc064) +#define GUC_DISABLE_SRAM_INIT_TO_ZEROES (1<<0) +#define GUC_ENABLE_READ_CACHE_LOGIC (1<<1) +#define GUC_ENABLE_MIA_CACHING (1<<2) +#define GUC_GEN10_MSGCH_ENABLE (1<<4) +#define GUC_ENABLE_READ_CACHE_FOR_SRAM_DATA (1<<9) +#define GUC_ENABLE_READ_CACHE_FOR_WOPCM_DATA (1<<10) +#define GUC_ENABLE_MIA_CLOCK_GATING (1<<15) +#define GUC_GEN10_SHIM_WC_ENABLE (1<<21) + +#define GUC_SHIM_CONTROL_VALUE (GUC_DISABLE_SRAM_INIT_TO_ZEROES | \ + GUC_ENABLE_READ_CACHE_LOGIC | \ + GUC_ENABLE_MIA_CACHING | \ + GUC_ENABLE_READ_CACHE_FOR_SRAM_DATA | \ + GUC_ENABLE_READ_CACHE_FOR_WOPCM_DATA) + +/* intel_guc_loader.c */ +extern int intel_guc_load_ucode(struct drm_device *dev); +extern void intel_guc_ucode_fini(struct drm_device *dev); +extern void intel_guc_ucode_init(struct drm_device *dev); + +#endif diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c new file mode 100644 index 0000000..a999044 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_guc_loader.c @@ -0,0 +1,348 @@ +/* + * Copyright © 2014 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + */ +#include <linux/firmware.h> +#include "i915_drv.h" +#include "intel_guc.h" + +/** + * DOC: GuC + * + * intel_guc: + * Top level structure of guc. It handles firmware loading and manages client + * pool and doorbells. intel_guc owns a i915_guc_client to replace the legacy + * ExecList submission. + * + * Firmware versioning: + * The firmware build process will generate a version header file with major and + * minor version defined. The versions are built into CSS header of firmware. + * i915 kernel driver set the minimal firmware version required per platform. + * The firmware installation package will install (symbolic link) proper version + * of firmware. + * + */ + +#define I915_SKL_GUC_UCODE "i915/skl_guc_ver1.bin" +MODULE_FIRMWARE(I915_SKL_GUC_UCODE); +#define I915_BXT_GUC_UCODE "i915/bxt_guc_ver1.bin" +MODULE_FIRMWARE(I915_BXT_GUC_UCODE); + +/* Read GuC status register (GUC_STATUS) + * Return true if get a success code from normal boot or RC6 boot + */ +static inline bool i915_guc_get_status(struct drm_i915_private *dev_priv, + u32 *status) +{ + *status = I915_READ(GUC_STATUS); + return (((*status) & GS_UKERNEL_MASK) == GS_UKERNEL_READY || + ((*status) & GS_UKERNEL_MASK) == GS_UKERNEL_LAPIC_DONE); +} + +/* Transfers the firmware image to RAM for execution by the microcontroller. + + * GuC Firmware layout: + * +-------------------------------+ ---- + * | CSS header | 128B + * +-------------------------------+ ---- + * | RSA signature | 256B + * +-------------------------------+ ---- + * | RSA public Key | 256B + * +-------------------------------+ ---- + * | Public key modulus | 4B + * +-------------------------------+ ---- + * | uCode | + * +-------------------------------+ ---- + * + * Architecturally, the DMA engine is bidirectional, and in can potentially + * even transfer between GTT locations. This functionality is left out of the + * API for now as there is no need for it. + * + * Be note that GuC need the CSS header plus uKernel code to be copied as one + * chunk of data. RSA sig data is loaded via MMIO. + */ +static int ucode_xfer_sync(struct drm_i915_private *dev_priv) +{ + struct intel_uc_fw *guc_fw = &dev_priv->guc.guc_fw; + struct drm_i915_gem_object *fw_obj = guc_fw->uc_fw_obj; + unsigned long offset; + struct sg_table *sg = fw_obj->pages; + u32 status, ucode_size, *blob; + int i, ret = 0; + + /* Copy RSA signature from the fw image to HW for verification */ + blob = (uint32_t *)(dev_priv->guc.guc_fw.uc_fw_blob->data + + UOS_RSA_SIG_OFFSET); + for (i = 0; i < UOS_RSA_SIG_SIZE / sizeof(uint32_t); i++) + I915_WRITE(UOS_RSA_SCRATCH_0 + i * sizeof(uint32_t), blob[i]); + + /* Re-arrange data per GuC request (CSS header + uCode) */ + + /* Copy CSS header */ + blob = (uint32_t *)(dev_priv->guc.guc_fw.uc_fw_blob->data + + UOS_CSS_HEADER_OFFSET); + sg_copy_from_buffer(sg->sgl, sg->nents, blob, UOS_CSS_HEADER_SIZE); + + /* Copy ucode */ + blob = (uint32_t *)(dev_priv->guc.guc_fw.uc_fw_blob->data + + UOS_UCODE_OFFSET); + ucode_size = guc_fw->uc_fw_size - UOS_UCODE_OFFSET; + sg_pcopy_from_buffer(sg->sgl, sg->nents, blob, + ucode_size, UOS_CSS_HEADER_SIZE); + + /* Set the source address for the new blob */ + offset = i915_gem_obj_ggtt_offset(fw_obj); + I915_WRITE(DMA_ADDR_0_LOW, lower_32_bits(offset)); + I915_WRITE(DMA_ADDR_0_HIGH, upper_32_bits(offset) & 0xFFFF); + + /* Set the destination. Current uCode expects an 8k stack starting from + * offset 0. */ + I915_WRITE(DMA_ADDR_1_LOW, 0x2000); + + /* XXX: The image is automatically transfered to SRAM after the RSA + * verification. This is why the address space is chosen as such. */ + I915_WRITE(DMA_ADDR_1_HIGH, DMA_ADDRESS_SPACE_WOPCM); + + I915_WRITE(DMA_COPY_SIZE, ucode_size + UOS_CSS_HEADER_SIZE); + + /* Finally start the DMA */ + I915_WRITE(DMA_CTRL, _MASKED_BIT_ENABLE(UOS_MOVE | START_DMA)); + + /* NB: Docs recommend not using the interrupt for completion. + * FIXME: what's a valid timeout? */ + ret = wait_for_atomic(i915_guc_get_status(dev_priv, &status), 10); + + DRM_DEBUG_DRIVER("DMA status = 0x%x, GuC status 0x%x\n", + I915_READ(DMA_CTRL), status); + + return ret; +} + +static u32 get_gttype(struct drm_device *dev) +{ + /* XXX: GT type based on PCI device ID? field seems unused by fw */ + return 0; +} + +static u32 get_core_family(struct drm_device *dev) +{ + switch (INTEL_INFO(dev)->gen) { + case 8: + return GFXCORE_FAMILY_GEN8; + case 9: + return GFXCORE_FAMILY_GEN9; + default: + DRM_ERROR("GUC: unknown gen for scheduler init\n"); + return GFXCORE_FAMILY_FORCE_ULONG; + } +} + +static void set_guc_init_params(struct drm_i915_private *dev_priv) +{ + u32 params[GUC_CTL_MAX_DWORDS]; + int i; + + memset(¶ms, 0, sizeof(params)); + + params[GUC_CTL_DEVICE_INFO] |= + (get_gttype(dev_priv->dev) << GUC_CTL_GTTYPE_SHIFT) | + (get_core_family(dev_priv->dev) << GUC_CTL_COREFAMILY_SHIFT); + + /* GuC ARAT increment is 10 ns. GuC default scheduler quantum is one + * second. This ARAR is calculated by: + * Scheduler-Quantum-in-ns / ARAT-increment-in-ns = 1000000000 / 10 + */ + params[GUC_CTL_ARAT_HIGH] = 0; + params[GUC_CTL_ARAT_LOW] = 100000000; + + params[GUC_CTL_WA] |= GUC_CTL_WA_UK_BY_DRIVER; + + params[GUC_CTL_FEATURE] |= GUC_CTL_DISABLE_SCHEDULER | + GUC_CTL_VCS2_ENABLED; + + /* XXX: Set up log buffer */ + + I915_WRITE(SOFT_SCRATCH(0), 0); + + for (i = 0; i < GUC_CTL_MAX_DWORDS; i++) + I915_WRITE(SOFT_SCRATCH(1 + i), params[i]); +} + +/* + * Loads the GuC firmware blob in to the MinuteIA. + */ +static int guc_load_ucode(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_uc_fw *guc_fw = &dev_priv->guc.guc_fw; + bool pinned = false; + int ret; + + WARN_ON(!mutex_is_locked(&dev->struct_mutex)); + + ret = i915_gem_obj_ggtt_pin(guc_fw->uc_fw_obj, 0, 0); + if (ret) + goto out; + pinned = true; + + /* Invalidate GuC TLB to let GuC take the latest updates to GTT. */ + I915_WRITE(GEN8_GTCR, GEN8_GTCR_INVALIDATE); + + /* Set MMIO/WA for GuC init */ + + /* Enable MIA caching. GuC clock gating is disabled. */ + I915_WRITE(GUC_SHIM_CONTROL, GUC_SHIM_CONTROL_VALUE); + + /* WaC6DisallowByGfxPause*/ + I915_WRITE(GEN6_GFXPAUSE, 0x30FFF); + + if (IS_GEN9(dev)) { + /* DOP Clock Gating Enable for GuC clocks */ + I915_WRITE(GEN7_MISCCPCTL, (GEN8_DOP_CLOCK_GATE_GUC_ENABLE | + I915_READ(GEN7_MISCCPCTL))); + + /* allows for 5us before GT can go to RC6 */ + I915_WRITE(GUC_ARAT_C6DIS, 0x1FF); + } + + set_guc_init_params(dev_priv); + + ret = ucode_xfer_sync(dev_priv); + + /* We can free the object pages now, and we would, except we might as + * well keep it around for suspend/resume. Instead, we just wait for the + * DMA to complete, and unpin the object + */ + +out: + DRM_DEBUG_DRIVER("return %d, pinned %d\n", ret, pinned); + + if (pinned) + i915_gem_object_ggtt_unpin(guc_fw->uc_fw_obj); + + return ret; +} + +/** + * intel_guc_load_ucode() - load ucode to hw + * + * Called from gem_init_hw() during driver loading and also after a GPU reset. + * Check that the firmware fetching process has succeeded, and if so transfer + * the loaded image to the hardware. + */ +int intel_guc_load_ucode(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_uc_fw *guc_fw = &dev_priv->guc.guc_fw; + int err; + + guc_fw->uc_fw_load_status = INTEL_UC_FIRMWARE_NONE; + if (guc_fw->uc_fw_fetch_status == INTEL_UC_FIRMWARE_NONE) + return 0; + + guc_fw->uc_fw_load_status = INTEL_UC_FIRMWARE_PENDING; + err = intel_uc_fw_check(dev, guc_fw); + if (err) + goto fail; + + err = guc_load_ucode(dev); + if (err) + goto fail; + + guc_fw->uc_fw_load_status = INTEL_UC_FIRMWARE_SUCCESS; + return 0; + +fail: + guc_fw->uc_fw_load_status = INTEL_UC_FIRMWARE_FAIL; + return err; +} + +/* + * Check the firmware that was found; return TRUE if acceptable. + * + * For the GuC, we just check the version number embedded at a well-known + * offset within the firmware blob; note that major / minor version are two + * bytes each - in *u16* + */ +static bool intel_guc_ucode_check(struct intel_uc_fw *guc_fw) +{ + uint32_t major, minor; + u8 *css_header = (u8 *)guc_fw->uc_fw_blob->data + UOS_CSS_HEADER_OFFSET; + + major = *(u16 *)(css_header + UOS_VER_MAJOR_OFFSET); + minor = *(u16 *)(css_header + UOS_VER_MINOR_OFFSET); + + if (major == guc_fw->uc_fw_ver_major && + minor >= guc_fw->uc_fw_ver_minor) { + DRM_DEBUG_DRIVER("firmware version %d.%d OK (minimum %d.%d)\n", + major, minor, + guc_fw->uc_fw_ver_major, guc_fw->uc_fw_ver_minor); + return true; + } + + DRM_ERROR("GuC firmware version %d.%d, required %d.%d\n", + major, minor, + guc_fw->uc_fw_ver_major, guc_fw->uc_fw_ver_minor); + return false; +} + +/** + * intel_guc_ucode_init() - init a firmware loading request + */ +void intel_guc_ucode_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_uc_fw *guc_fw = &dev_priv->guc.guc_fw; + const char *path = NULL; + + if (!HAS_GUC_UCODE(dev)) { + guc_fw->uc_fw_fetch_status = INTEL_UC_FIRMWARE_NONE; + guc_fw->uc_fw_load_status = INTEL_UC_FIRMWARE_NONE; + return; + } + + if (IS_SKYLAKE(dev)) { + path = I915_SKL_GUC_UCODE; + guc_fw->uc_fw_ver_major = 1; + guc_fw->uc_fw_ver_minor = 0; + guc_fw->uc_fw_check = intel_guc_ucode_check; + } + else if (IS_BROXTON(dev)) { + path = I915_BXT_GUC_UCODE; + guc_fw->uc_fw_ver_major = 1; + guc_fw->uc_fw_ver_minor = 0; + guc_fw->uc_fw_check = intel_guc_ucode_check; + } + + intel_uc_fw_init(dev, guc_fw, "GuC", path); +} + +/** + * intel_guc_ucode_fini() - clean up firmware blob allocated + */ +void intel_guc_ucode_fini(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_uc_fw *guc_fw = &dev_priv->guc.guc_fw; + + intel_uc_fw_fini(dev, guc_fw); +} diff --git a/drivers/gpu/drm/i915/intel_uc_loader.c b/drivers/gpu/drm/i915/intel_uc_loader.c index bc499f4..65031ff 100644 --- a/drivers/gpu/drm/i915/intel_uc_loader.c +++ b/drivers/gpu/drm/i915/intel_uc_loader.c @@ -77,6 +77,9 @@ static void uc_fw_finish(struct drm_device *dev, struct intel_uc_fw *uc_fw) uc_fw->uc_fw_blob = fw; } + if (uc_fw->uc_fw_check && !uc_fw->uc_fw_check(uc_fw)) + goto fail; + obj = i915_gem_alloc_object(dev, round_up(fw->size, PAGE_SIZE)); if (!obj) goto fail; diff --git a/drivers/gpu/drm/i915/intel_uc_loader.h b/drivers/gpu/drm/i915/intel_uc_loader.h index 0994f98..4ed6e94 100644 --- a/drivers/gpu/drm/i915/intel_uc_loader.h +++ b/drivers/gpu/drm/i915/intel_uc_loader.h @@ -68,11 +68,15 @@ struct intel_uc_fw { struct drm_i915_gem_object * uc_fw_obj; enum intel_uc_fw_status uc_fw_fetch_status; enum intel_uc_fw_status uc_fw_load_status; + uint32_t uc_fw_ver_major; + uint32_t uc_fw_ver_minor; + bool (*uc_fw_check)(struct intel_uc_fw *); }; void intel_uc_fw_init(struct drm_device *dev, struct intel_uc_fw *uc_fw, const char *uc_name, const char *fw_path); int intel_uc_fw_check(struct drm_device *dev, struct intel_uc_fw *uc_fw); void intel_uc_fw_fini(struct drm_device *dev, struct intel_uc_fw *uc_fw); +bool intel_uc_fw_version_check(struct intel_uc_fw *fw, const char *data); #endif -- 1.9.1 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx