@ -21,6 +21,7 @@
*/
# include "common.h"
# include <command.h>
# include "asm/errno.h"
# include "asm/io.h"
# include "asm/immap_qe.h"
@ -248,4 +249,222 @@ int qe_set_mii_clk_src(int ucc_num)
return 0 ;
}
/* The maximum number of RISCs we support */
# define MAX_QE_RISC 2
/* Firmware information stored here for qe_get_firmware_info() */
static struct qe_firmware_info qe_firmware_info ;
/*
* Set to 1 if QE firmware has been uploaded , and therefore
* qe_firmware_info contains valid data .
*/
static int qe_firmware_uploaded ;
/*
* Upload a QE microcode
*
* This function is a worker function for qe_upload_firmware ( ) . It does
* the actual uploading of the microcode .
*/
static void qe_upload_microcode ( const void * base ,
const struct qe_microcode * ucode )
{
const u32 * code = base + be32_to_cpu ( ucode - > code_offset ) ;
unsigned int i ;
if ( ucode - > major | | ucode - > minor | | ucode - > revision )
printf ( " QE: uploading microcode '%s' version %u.%u.%u \n " ,
ucode - > id , ucode - > major , ucode - > minor , ucode - > revision ) ;
else
printf ( " QE: uploading microcode '%s' \n " , ucode - > id ) ;
/* Use auto-increment */
out_be32 ( & qe_immr - > iram . iadd , be32_to_cpu ( ucode - > iram_offset ) |
QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR ) ;
for ( i = 0 ; i < be32_to_cpu ( ucode - > count ) ; i + + )
out_be32 ( & qe_immr - > iram . idata , be32_to_cpu ( code [ i ] ) ) ;
}
/*
* 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 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 ;
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 " ) ;
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 ) ;
/*
* The QE only supports one microcode per RISC , so clear out all the
* saved microcode information and put in the new .
*/
memset ( & qe_firmware_info , 0 , sizeof ( qe_firmware_info ) ) ;
strcpy ( qe_firmware_info . id , firmware - > id ) ;
qe_firmware_info . extended_modes = firmware - > extended_modes ;
memcpy ( qe_firmware_info . vtraps , firmware - > vtraps ,
sizeof ( firmware - > vtraps ) ) ;
qe_firmware_uploaded = 1 ;
/* 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 ;
}
struct qe_firmware_info * qe_get_firmware_info ( void )
{
return qe_firmware_uploaded ? & qe_firmware_info : NULL ;
}
static int qe_cmd ( cmd_tbl_t * cmdtp , int flag , int argc , char * argv [ ] )
{
ulong addr ;
if ( argc < 3 ) {
printf ( " Usage: \n %s \n " , cmdtp - > usage ) ;
return 1 ;
}
if ( strcmp ( argv [ 1 ] , " fw " ) = = 0 ) {
addr = simple_strtoul ( argv [ 2 ] , NULL , 16 ) ;
if ( ! addr ) {
printf ( " Invalid address \n " ) ;
return - EINVAL ;
}
/*
* If a length was supplied , compare that with the ' length '
* field .
*/
if ( argc > 3 ) {
ulong length = simple_strtoul ( argv [ 3 ] , NULL , 16 ) ;
struct qe_firmware * firmware = ( void * ) addr ;
if ( length ! = be32_to_cpu ( firmware - > header . length ) ) {
printf ( " Length mismatch \n " ) ;
return - EINVAL ;
}
}
return qe_upload_firmware ( ( const struct qe_firmware * ) addr ) ;
}
printf ( " Usage: \n %s \n " , cmdtp - > usage ) ;
return 1 ;
}
U_BOOT_CMD (
qe , 4 , 0 , qe_cmd ,
" qe - QUICC Engine commands \n " ,
" fw <addr> [<length>] - Upload firmware binary at address <addr> to "
" the QE, \n \t with optional length <length> verification. \n "
) ;
# endif /* CONFIG_QE */