@ -188,7 +188,7 @@ void u_qe_init(void)
uint qe_base = CONFIG_SYS_IMMR + 0x01400000 ; /* QE immr base */
qe_immr = ( qe_map_t * ) qe_base ;
qe_upload_firmware ( ( const void * ) CONFIG_SYS_QE_FW_ADDR ) ;
u_ qe_upload_firmware( ( const void * ) CONFIG_SYS_QE_FW_ADDR ) ;
out_be32 ( & qe_immr - > iram . iready , QE_IRAM_READY ) ;
}
# endif
@ -444,6 +444,131 @@ int qe_upload_firmware(const struct qe_firmware *firmware)
return 0 ;
}
# ifdef CONFIG_U_QE
/*
* Upload a microcode to the I - RAM at a specific address .
*
* See docs / README . qe_firmware for information on QE microcode uploading .
*
* Currently , only version 1 is supported , so the ' version ' field must be
* set to 1.
*
* The SOC model and revision are not validated , they are only displayed for
* informational purposes .
*
* ' calc_size ' is the calculated size , in bytes , of the firmware structure and
* all of the microcode structures , minus the CRC .
*
* ' length ' is the size that the structure says it is , including the CRC .
*/
int u_qe_upload_firmware ( const struct qe_firmware * firmware )
{
unsigned int i ;
unsigned int j ;
u32 crc ;
size_t calc_size = sizeof ( struct qe_firmware ) ;
size_t length ;
const struct qe_header * hdr ;
# ifdef CONFIG_DEEP_SLEEP
ccsr_gur_t __iomem * gur = ( void * ) ( CONFIG_SYS_MPC85xx_GUTS_ADDR ) ;
# endif
if ( ! firmware ) {
printf ( " Invalid address \n " ) ;
return - EINVAL ;
}
hdr = & firmware - > header ;
length = be32_to_cpu ( hdr - > length ) ;
/* Check the magic */
if ( ( hdr - > magic [ 0 ] ! = ' Q ' ) | | ( hdr - > magic [ 1 ] ! = ' E ' ) | |
( hdr - > magic [ 2 ] ! = ' F ' ) ) {
printf ( " Not a microcode \n " ) ;
# ifdef CONFIG_DEEP_SLEEP
setbits_be32 ( & gur - > devdisr , MPC85xx_DEVDISR_QE_DISABLE ) ;
# endif
return - EPERM ;
}
/* Check the version */
if ( hdr - > version ! = 1 ) {
printf ( " Unsupported version \n " ) ;
return - EPERM ;
}
/* Validate some of the fields */
if ( ( firmware - > count < 1 ) | | ( firmware - > count > MAX_QE_RISC ) ) {
printf ( " Invalid data \n " ) ;
return - EINVAL ;
}
/* Validate the length and check if there's a CRC */
calc_size + = ( firmware - > count - 1 ) * sizeof ( struct qe_microcode ) ;
for ( i = 0 ; i < firmware - > count ; i + + )
/*
* For situations where the second RISC uses the same microcode
* as the first , the ' code_offset ' and ' count ' fields will be
* zero , so it ' s okay to add those .
*/
calc_size + = sizeof ( u32 ) *
be32_to_cpu ( firmware - > microcode [ i ] . count ) ;
/* Validate the length */
if ( length ! = calc_size + sizeof ( u32 ) ) {
printf ( " Invalid length \n " ) ;
return - EPERM ;
}
/*
* Validate the CRC . We would normally call crc32_no_comp ( ) , but that
* function isn ' t available unless you turn on JFFS support .
*/
crc = be32_to_cpu ( * ( u32 * ) ( ( void * ) firmware + calc_size ) ) ;
if ( crc ! = ( crc32 ( - 1 , ( const void * ) firmware , calc_size ) ^ - 1 ) ) {
printf ( " Firmware CRC is invalid \n " ) ;
return - EIO ;
}
/*
* If the microcode calls for it , split the I - RAM .
*/
if ( ! firmware - > split ) {
out_be16 ( & qe_immr - > cp . cercr ,
in_be16 ( & qe_immr - > cp . cercr ) | QE_CP_CERCR_CIR ) ;
}
if ( firmware - > soc . model )
printf ( " Firmware '%s' for %u V%u.%u \n " ,
firmware - > id , be16_to_cpu ( firmware - > soc . model ) ,
firmware - > soc . major , firmware - > soc . minor ) ;
else
printf ( " Firmware '%s' \n " , firmware - > id ) ;
/* Loop through each microcode. */
for ( i = 0 ; i < firmware - > count ; i + + ) {
const struct qe_microcode * ucode = & firmware - > microcode [ i ] ;
/* Upload a microcode if it's present */
if ( ucode - > code_offset )
qe_upload_microcode ( firmware , ucode ) ;
/* Program the traps for this processor */
for ( j = 0 ; j < 16 ; j + + ) {
u32 trap = be32_to_cpu ( ucode - > traps [ j ] ) ;
if ( trap )
out_be32 ( & qe_immr - > rsp [ i ] . tibcr [ j ] , trap ) ;
}
/* Enable traps */
out_be32 ( & qe_immr - > rsp [ i ] . eccr , be32_to_cpu ( ucode - > eccr ) ) ;
}
return 0 ;
}
# endif
struct qe_firmware_info * qe_get_firmware_info ( void )
{
return qe_firmware_uploaded ? & qe_firmware_info : NULL ;