2019-08-12 09:29:35 +00:00
// SPDX-License-Identifier: MIT
2015-08-12 15:43:36 +01:00
/*
2019-08-12 09:29:35 +00:00
* Copyright © 2014 - 2019 Intel Corporation
2015-08-12 15:43:36 +01:00
*
* Authors :
* Vinit Azad < vinit . azad @ intel . com >
* Ben Widawsky < ben @ bwidawsk . net >
* Dave Gordon < david . s . gordon @ intel . com >
* Alex Dai < yu . dai @ intel . com >
*/
2017-10-16 14:47:14 +00:00
2019-07-13 11:00:14 +01:00
# include "gt/intel_gt.h"
2017-10-16 14:47:14 +00:00
# include "intel_guc_fw.h"
2015-08-12 15:43:36 +01:00
# include "i915_drv.h"
2019-07-24 17:18:12 -07:00
static void guc_prepare_xfer ( struct intel_uncore * uncore )
2015-08-12 15:43:36 +01:00
{
2019-07-13 11:00:14 +01:00
u32 shim_flags = 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 |
GUC_ENABLE_MIA_CLOCK_GATING ;
2017-11-03 15:18:12 +00:00
2017-11-03 15:18:15 +00:00
/* Must program this register before loading the ucode with DMA */
2019-07-13 11:00:14 +01:00
intel_uncore_write ( uncore , GUC_SHIM_CONTROL , shim_flags ) ;
2019-07-24 17:18:12 -07:00
if ( IS_GEN9_LP ( uncore - > i915 ) )
2019-07-13 11:00:14 +01:00
intel_uncore_write ( uncore , GEN9LP_GT_PM_CONFIG , GT_DOORBELL_ENABLE ) ;
2017-11-03 15:18:12 +00:00
else
2019-07-13 11:00:14 +01:00
intel_uncore_write ( uncore , GEN9_GT_PM_CONFIG , GT_DOORBELL_ENABLE ) ;
2017-11-03 15:18:12 +00:00
2019-07-24 17:18:12 -07:00
if ( IS_GEN ( uncore - > i915 , 9 ) ) {
2017-11-03 15:18:12 +00:00
/* DOP Clock Gating Enable for GuC clocks */
2019-07-13 11:00:14 +01:00
intel_uncore_rmw ( uncore , GEN7_MISCCPCTL ,
0 , GEN8_DOP_CLOCK_GATE_GUC_ENABLE ) ;
2017-11-03 15:18:12 +00:00
/* allows for 5us (in 10ns units) before GT can go to RC6 */
2019-07-13 11:00:14 +01:00
intel_uncore_write ( uncore , GUC_ARAT_C6DIS , 0x1FF ) ;
2017-11-03 15:18:12 +00:00
}
}
/* Copy RSA signature from the fw image to HW for verification */
2019-07-24 17:18:12 -07:00
static void guc_xfer_rsa ( struct intel_uc_fw * guc_fw ,
struct intel_uncore * uncore )
2017-11-03 15:18:12 +00:00
{
2017-11-24 17:02:39 +00:00
u32 rsa [ UOS_RSA_SCRATCH_COUNT ] ;
2019-07-24 17:18:10 -07:00
size_t copied ;
2017-11-03 15:18:12 +00:00
int i ;
2019-07-24 17:18:12 -07:00
copied = intel_uc_fw_copy_rsa ( guc_fw , rsa , sizeof ( rsa ) ) ;
2019-07-24 17:18:10 -07:00
GEM_BUG_ON ( copied < sizeof ( rsa ) ) ;
2017-11-03 15:18:12 +00:00
2017-11-24 17:02:39 +00:00
for ( i = 0 ; i < UOS_RSA_SCRATCH_COUNT ; i + + )
2019-07-13 11:00:14 +01:00
intel_uncore_write ( uncore , UOS_RSA_SCRATCH ( i ) , rsa [ i ] ) ;
2015-08-12 15:43:36 +01:00
}
2017-11-03 15:18:12 +00:00
/*
* Read the GuC status register ( GUC_STATUS ) and store it in the
* specified location ; then return a boolean indicating whether
* the value matches either of two values representing completion
* of the GuC boot process .
*
* This is used for polling the GuC status in a wait_for ( )
* loop below .
*/
2019-07-13 11:00:14 +01:00
static inline bool guc_ready ( struct intel_uncore * uncore , u32 * status )
2017-11-03 15:18:12 +00:00
{
2019-07-13 11:00:14 +01:00
u32 val = intel_uncore_read ( uncore , GUC_STATUS ) ;
2017-11-03 15:18:12 +00:00
u32 uk_val = val & GS_UKERNEL_MASK ;
* status = val ;
return ( uk_val = = GS_UKERNEL_READY ) | |
( ( val & GS_MIA_CORE_STATE ) & & ( uk_val = = GS_UKERNEL_LAPIC_DONE ) ) ;
}
2019-07-13 11:00:14 +01:00
static int guc_wait_ucode ( struct intel_uncore * uncore )
2017-11-03 15:18:12 +00:00
{
u32 status ;
int ret ;
2015-08-12 15:43:36 +01:00
/*
2017-11-03 15:18:12 +00:00
* Wait for the GuC to start up .
2015-08-12 15:43:36 +01:00
* NB : Docs recommend not using the interrupt for completion .
* Measurements indicate this should take no more than 20 ms , so a
* timeout here indicates that the GuC has failed and is unusable .
2018-10-22 16:04:25 -07:00
* ( Higher levels of the driver may decide to reset the GuC and
* attempt the ucode load again if this happens . )
2015-08-12 15:43:36 +01:00
*/
2019-07-13 11:00:14 +01:00
ret = wait_for ( guc_ready ( uncore , & status ) , 100 ) ;
2017-11-03 15:18:12 +00:00
DRM_DEBUG_DRIVER ( " GuC status %#x \n " , status ) ;
2015-08-12 15:43:36 +01:00
if ( ( status & GS_BOOTROM_MASK ) = = GS_BOOTROM_RSA_FAILED ) {
DRM_ERROR ( " GuC firmware signature verification failed \n " ) ;
ret = - ENOEXEC ;
}
2019-06-25 09:41:07 -07:00
if ( ( status & GS_UKERNEL_MASK ) = = GS_UKERNEL_EXCEPTION ) {
DRM_ERROR ( " GuC firmware exception. EIP: %#x \n " ,
2019-07-13 11:00:14 +01:00
intel_uncore_read ( uncore , SOFT_SCRATCH ( 13 ) ) ) ;
2019-06-25 09:41:07 -07:00
ret = - ENXIO ;
}
2015-08-12 15:43:36 +01:00
return ret ;
}
2019-07-24 17:18:13 -07:00
/**
* intel_guc_fw_upload ( ) - load GuC uCode to device
* @ guc : intel_guc structure
2018-10-18 20:55:36 +01:00
*
2019-07-24 17:18:13 -07:00
* Called from intel_uc_init_hw ( ) during driver load , resume from sleep and
* after a GPU reset .
*
* The firmware image should have already been fetched into memory , so only
* check that fetch succeeded , and then transfer the image to the h / w .
*
* Return : non - zero code on error
2015-08-12 15:43:36 +01:00
*/
2019-07-24 17:18:13 -07:00
int intel_guc_fw_upload ( struct intel_guc * guc )
2015-08-12 15:43:36 +01:00
{
2019-07-24 17:18:13 -07:00
struct intel_gt * gt = guc_to_gt ( guc ) ;
2019-07-24 17:18:12 -07:00
struct intel_uncore * uncore = gt - > uncore ;
2015-08-12 15:43:36 +01:00
int ret ;
2019-07-24 17:18:12 -07:00
guc_prepare_xfer ( uncore ) ;
2015-08-12 15:43:36 +01:00
2017-11-03 15:18:12 +00:00
/*
* Note that GuC needs the CSS header plus uKernel code to be copied
* by the DMA engine in one operation , whereas the RSA signature is
* loaded via MMIO .
*/
2019-07-24 17:18:13 -07:00
guc_xfer_rsa ( & guc - > fw , uncore ) ;
2015-08-12 15:43:36 +01:00
2019-07-24 17:18:13 -07:00
/*
* Current uCode expects the code to be loaded at 8 k ; locations below
* this are used for the stack .
*/
2019-12-11 12:45:48 +00:00
ret = intel_uc_fw_upload ( & guc - > fw , 0x2000 , UOS_MOVE ) ;
2019-07-24 17:18:13 -07:00
if ( ret )
goto out ;
2015-08-12 15:43:36 +01:00
2019-07-24 17:18:13 -07:00
ret = guc_wait_ucode ( uncore ) ;
if ( ret )
goto out ;
2015-08-12 15:43:36 +01:00
2019-08-13 08:15:59 +00:00
intel_uc_fw_change_status ( & guc - > fw , INTEL_UC_FIRMWARE_RUNNING ) ;
2019-07-24 17:18:13 -07:00
return 0 ;
2019-07-24 17:18:09 -07:00
2019-07-24 17:18:13 -07:00
out :
2019-08-13 08:15:59 +00:00
intel_uc_fw_change_status ( & guc - > fw , INTEL_UC_FIRMWARE_FAIL ) ;
2019-07-24 17:18:09 -07:00
return ret ;
2015-08-12 15:43:36 +01:00
}