Commit bc556ba9 authored by Timur Tabi's avatar Timur Tabi Committed by Kumar Gala

[POWERPC] QE: Add ability to upload QE firmware

Define the layout of a binary blob that contains a QE firmware and instructions
on how to upload it.  Add function qe_upload_firmware() to parse the blob
and perform the actual upload.  Fully define 'struct rsp' in immap_qe.h to
include the actual RISC Special Registers.  Added description of a new
QE firmware node to booting-without-of.txt.
Signed-off-by: default avatarTimur Tabi <timur@freescale.com>
Signed-off-by: default avatarKumar Gala <galak@kernel.crashing.org>
parent a21e282a
...@@ -28,3 +28,6 @@ sound.txt ...@@ -28,3 +28,6 @@ sound.txt
- info on sound support under Linux/PPC - info on sound support under Linux/PPC
zImage_layout.txt zImage_layout.txt
- info on the kernel images for Linux/PPC - info on the kernel images for Linux/PPC
qe_firmware.txt
- describes the layout of firmware binaries for the Freescale QUICC
Engine and the code that parses and uploads the microcode therein.
...@@ -52,7 +52,10 @@ Table of Contents ...@@ -52,7 +52,10 @@ Table of Contents
i) Freescale QUICC Engine module (QE) i) Freescale QUICC Engine module (QE)
j) CFI or JEDEC memory-mapped NOR flash j) CFI or JEDEC memory-mapped NOR flash
k) Global Utilities Block k) Global Utilities Block
l) Xilinx IP cores l) Freescale Communications Processor Module
m) Chipselect/Local Bus
n) 4xx/Axon EMAC ethernet nodes
o) Xilinx IP cores
VII - Specifying interrupt information for devices VII - Specifying interrupt information for devices
1) interrupts property 1) interrupts property
...@@ -1788,6 +1791,32 @@ platforms are moved over to use the flattened-device-tree model. ...@@ -1788,6 +1791,32 @@ platforms are moved over to use the flattened-device-tree model.
}; };
}; };
viii) Uploaded QE firmware
If a new firwmare has been uploaded to the QE (usually by the
boot loader), then a 'firmware' child node should be added to the QE
node. This node provides information on the uploaded firmware that
device drivers may need.
Required properties:
- id: The string name of the firmware. This is taken from the 'id'
member of the qe_firmware structure of the uploaded firmware.
Device drivers can search this string to determine if the
firmware they want is already present.
- extended-modes: The Extended Modes bitfield, taken from the
firmware binary. It is a 64-bit number represented
as an array of two 32-bit numbers.
- virtual-traps: The virtual traps, taken from the firmware binary.
It is an array of 8 32-bit numbers.
Example:
firmware {
id = "Soft-UART";
extended-modes = <0 0>;
virtual-traps = <0 0 0 0 0 0 0 0>;
}
j) CFI or JEDEC memory-mapped NOR flash j) CFI or JEDEC memory-mapped NOR flash
Flash chips (Memory Technology Devices) are often used for solid state Flash chips (Memory Technology Devices) are often used for solid state
...@@ -2269,7 +2298,7 @@ platforms are moved over to use the flattened-device-tree model. ...@@ -2269,7 +2298,7 @@ platforms are moved over to use the flattened-device-tree model.
available. available.
For Axon: 0x0000012a For Axon: 0x0000012a
l) Xilinx IP cores o) Xilinx IP cores
The Xilinx EDK toolchain ships with a set of IP cores (devices) for use The Xilinx EDK toolchain ships with a set of IP cores (devices) for use
in Xilinx Spartan and Virtex FPGAs. The devices cover the whole range in Xilinx Spartan and Virtex FPGAs. The devices cover the whole range
......
This diff is collapsed.
...@@ -265,6 +265,7 @@ config TAU_AVERAGE ...@@ -265,6 +265,7 @@ config TAU_AVERAGE
config QUICC_ENGINE config QUICC_ENGINE
bool bool
select PPC_LIB_RHEAP select PPC_LIB_RHEAP
select CRC32
help help
The QUICC Engine (QE) is a new generation of communications The QUICC Engine (QE) is a new generation of communications
coprocessors on Freescale embedded CPUs (akin to CPM in older chips). coprocessors on Freescale embedded CPUs (akin to CPM in older chips).
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/crc32.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/page.h> #include <asm/page.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
...@@ -394,3 +395,249 @@ void *qe_muram_addr(unsigned long offset) ...@@ -394,3 +395,249 @@ void *qe_muram_addr(unsigned long offset)
return (void *)&qe_immr->muram[offset]; return (void *)&qe_immr->muram[offset];
} }
EXPORT_SYMBOL(qe_muram_addr); EXPORT_SYMBOL(qe_muram_addr);
/* 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 __be32 *code = base + be32_to_cpu(ucode->code_offset);
unsigned int i;
if (ucode->major || ucode->minor || ucode->revision)
printk(KERN_INFO "qe-firmware: "
"uploading microcode '%s' version %u.%u.%u\n",
ucode->id, ucode->major, ucode->minor, ucode->revision);
else
printk(KERN_INFO "qe-firmware: "
"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 Documentation/powerpc/qe-firmware.txt 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) {
printk(KERN_ERR "qe-firmware: invalid pointer\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')) {
printk(KERN_ERR "qe-firmware: not a microcode\n");
return -EPERM;
}
/* Check the version */
if (hdr->version != 1) {
printk(KERN_ERR "qe-firmware: unsupported version\n");
return -EPERM;
}
/* Validate some of the fields */
if ((firmware->count < 1) || (firmware->count >= MAX_QE_RISC)) {
printk(KERN_ERR "qe-firmware: 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(__be32) *
be32_to_cpu(firmware->microcode[i].count);
/* Validate the length */
if (length != calc_size + sizeof(__be32)) {
printk(KERN_ERR "qe-firmware: invalid length\n");
return -EPERM;
}
/* Validate the CRC */
crc = be32_to_cpu(*(__be32 *)((void *)firmware + calc_size));
if (crc != crc32(0, firmware, calc_size)) {
printk(KERN_ERR "qe-firmware: firmware CRC is invalid\n");
return -EIO;
}
/*
* If the microcode calls for it, split the I-RAM.
*/
if (!firmware->split)
setbits16(&qe_immr->cp.cercr, QE_CP_CERCR_CIR);
if (firmware->soc.model)
printk(KERN_INFO
"qe-firmware: firmware '%s' for %u V%u.%u\n",
firmware->id, be16_to_cpu(firmware->soc.model),
firmware->soc.major, firmware->soc.minor);
else
printk(KERN_INFO "qe-firmware: 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));
/* 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));
}
qe_firmware_uploaded = 1;
return 0;
}
EXPORT_SYMBOL(qe_upload_firmware);
/*
* Get info on the currently-loaded firmware
*
* This function also checks the device tree to see if the boot loader has
* uploaded a firmware already.
*/
struct qe_firmware_info *qe_get_firmware_info(void)
{
static int initialized;
struct property *prop;
struct device_node *qe;
struct device_node *fw = NULL;
const char *sprop;
unsigned int i;
/*
* If we haven't checked yet, and a driver hasn't uploaded a firmware
* yet, then check the device tree for information.
*/
if (initialized || qe_firmware_uploaded)
return NULL;
initialized = 1;
/*
* Newer device trees have an "fsl,qe" compatible property for the QE
* node, but we still need to support older device trees.
*/
qe = of_find_compatible_node(NULL, NULL, "fsl,qe");
if (!qe) {
qe = of_find_node_by_type(NULL, "qe");
if (!qe)
return NULL;
}
/* Find the 'firmware' child node */
for_each_child_of_node(qe, fw) {
if (strcmp(fw->name, "firmware") == 0)
break;
}
of_node_put(qe);
/* Did we find the 'firmware' node? */
if (!fw)
return NULL;
qe_firmware_uploaded = 1;
/* Copy the data into qe_firmware_info*/
sprop = of_get_property(fw, "id", NULL);
if (sprop)
strncpy(qe_firmware_info.id, sprop,
sizeof(qe_firmware_info.id) - 1);
prop = of_find_property(fw, "extended-modes", NULL);
if (prop && (prop->length == sizeof(u64))) {
const u64 *iprop = prop->value;
qe_firmware_info.extended_modes = *iprop;
}
prop = of_find_property(fw, "virtual-traps", NULL);
if (prop && (prop->length == 32)) {
const u32 *iprop = prop->value;
for (i = 0; i < ARRAY_SIZE(qe_firmware_info.vtraps); i++)
qe_firmware_info.vtraps[i] = iprop[i];
}
of_node_put(fw);
return &qe_firmware_info;
}
EXPORT_SYMBOL(qe_get_firmware_info);
...@@ -393,9 +393,39 @@ struct dbg { ...@@ -393,9 +393,39 @@ struct dbg {
u8 res2[0x48]; u8 res2[0x48];
} __attribute__ ((packed)); } __attribute__ ((packed));
/* RISC Special Registers (Trap and Breakpoint) */ /*
* RISC Special Registers (Trap and Breakpoint). These are described in
* the QE Developer's Handbook.
*/
struct rsp { struct rsp {
u32 reg[0x40]; /* 64 32-bit registers */ __be32 tibcr[16]; /* Trap/instruction breakpoint control regs */
u8 res0[64];
__be32 ibcr0;
__be32 ibs0;
__be32 ibcnr0;
u8 res1[4];
__be32 ibcr1;
__be32 ibs1;
__be32 ibcnr1;
__be32 npcr;
__be32 dbcr;
__be32 dbar;
__be32 dbamr;
__be32 dbsr;
__be32 dbcnr;
u8 res2[12];
__be32 dbdr_h;
__be32 dbdr_l;
__be32 dbdmr_h;
__be32 dbdmr_l;
__be32 bsr;
__be32 bor;
__be32 bior;
u8 res3[4];
__be32 iatr[4];
__be32 eccr; /* Exception control configuration register */
__be32 eicr;
u8 res4[0x100-0xf8];
} __attribute__ ((packed)); } __attribute__ ((packed));
struct qe_immap { struct qe_immap {
......
...@@ -94,6 +94,58 @@ unsigned long qe_muram_alloc_fixed(unsigned long offset, int size); ...@@ -94,6 +94,58 @@ unsigned long qe_muram_alloc_fixed(unsigned long offset, int size);
void qe_muram_dump(void); void qe_muram_dump(void);
void *qe_muram_addr(unsigned long offset); void *qe_muram_addr(unsigned long offset);
/* Structure that defines QE firmware binary files.
*
* See Documentation/powerpc/qe-firmware.txt for a description of these
* fields.
*/
struct qe_firmware {
struct qe_header {
__be32 length; /* Length of the entire structure, in bytes */
u8 magic[3]; /* Set to { 'Q', 'E', 'F' } */
u8 version; /* Version of this layout. First ver is '1' */
} header;
u8 id[62]; /* Null-terminated identifier string */
u8 split; /* 0 = shared I-RAM, 1 = split I-RAM */
u8 count; /* Number of microcode[] structures */
struct {
__be16 model; /* The SOC model */
u8 major; /* The SOC revision major */
u8 minor; /* The SOC revision minor */
} __attribute__ ((packed)) soc;
u8 padding[4]; /* Reserved, for alignment */
__be64 extended_modes; /* Extended modes */
__be32 vtraps[8]; /* Virtual trap addresses */
u8 reserved[4]; /* Reserved, for future expansion */
struct qe_microcode {
u8 id[32]; /* Null-terminated identifier */
__be32 traps[16]; /* Trap addresses, 0 == ignore */
__be32 eccr; /* The value for the ECCR register */
__be32 iram_offset; /* Offset into I-RAM for the code */
__be32 count; /* Number of 32-bit words of the code */
__be32 code_offset; /* Offset of the actual microcode */
u8 major; /* The microcode version major */
u8 minor; /* The microcode version minor */
u8 revision; /* The microcode version revision */
u8 padding; /* Reserved, for alignment */
u8 reserved[4]; /* Reserved, for future expansion */
} __attribute__ ((packed)) microcode[1];
/* All microcode binaries should be located here */
/* CRC32 should be located here, after the microcode binaries */
} __attribute__ ((packed));
struct qe_firmware_info {
char id[64]; /* Firmware name */
u32 vtraps[8]; /* Virtual trap addresses */
u64 extended_modes; /* Extended modes */
};
/* Upload a firmware to the QE */
int qe_upload_firmware(const struct qe_firmware *firmware);
/* Obtain information on the uploaded firmware */
struct qe_firmware_info *qe_get_firmware_info(void);
/* Buffer descriptors */ /* Buffer descriptors */
struct qe_bd { struct qe_bd {
__be16 status; __be16 status;
...@@ -329,6 +381,15 @@ enum comm_dir { ...@@ -329,6 +381,15 @@ enum comm_dir {
#define QE_SDEBCR_BA_MASK 0x01FFFFFF #define QE_SDEBCR_BA_MASK 0x01FFFFFF
/* Communication Processor */
#define QE_CP_CERCR_MEE 0x8000 /* Multi-user RAM ECC enable */
#define QE_CP_CERCR_IEE 0x4000 /* Instruction RAM ECC enable */
#define QE_CP_CERCR_CIR 0x0800 /* Common instruction RAM */
/* I-RAM */
#define QE_IRAM_IADD_AIE 0x80000000 /* Auto Increment Enable */
#define QE_IRAM_IADD_BADDR 0x00080000 /* Base Address */
/* UPC */ /* UPC */
#define UPGCR_PROTOCOL 0x80000000 /* protocol ul2 or pl2 */ #define UPGCR_PROTOCOL 0x80000000 /* protocol ul2 or pl2 */
#define UPGCR_TMS 0x40000000 /* Transmit master/slave mode */ #define UPGCR_TMS 0x40000000 /* Transmit master/slave mode */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment