Define the layout of a binary blob that contains a QE firmware and instructions
on how to upload it.  Add function qe_upload_microcode() to parse the blob
and perform the actual upload.  Fully define 'struct rsp' in immap_qe.h to
include the actual RISC Special Registers.

Signed-off-by: Timur Tabi <[EMAIL PROTECTED]>
---

This patch applies on top of my previous patches
"qe: add function qe_clock_source" and
"ucc_geth: use rx-clock-name and tx-clock-name device tree properties".

This patch defines a new specification for a QE binary file.  Please review
the specification as well as the code.

 arch/powerpc/sysdev/qe_lib/qe.c |   96 +++++++++++++++++++++++++++++
 include/asm-powerpc/immap_qe.h  |   29 ++++++++-
 include/asm-powerpc/qe.h        |  128 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 251 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/arch/powerpc/sysdev/qe_lib/qe.c
index 8551e74..7ca398c 100644
--- a/arch/powerpc/sysdev/qe_lib/qe.c
+++ b/arch/powerpc/sysdev/qe_lib/qe.c
@@ -25,6 +25,7 @@
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/ioport.h>
+#include <linux/crc32.h>
 #include <asm/irq.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -393,3 +394,98 @@ void *qe_muram_addr(unsigned long offset)
        return (void *)&qe_immr->muram[offset];
 }
 EXPORT_SYMBOL(qe_muram_addr);
+
+/*
+ * Download a microcode to the I-RAM at a specific address.
+ *
+ * @firmware: pointer to qe_firmware structure
+ */
+int qe_upload_microcode(const struct qe_firmware *firmware)
+{
+       unsigned int i;
+       unsigned int j;
+       __be32 *code;
+       u32 crc;
+       size_t length = sizeof(struct qe_firmware);
+
+       /* Check the magic and version number */
+       if ((firmware->magic[0] != 'Q') || (firmware->magic[1] != 'E') ||
+           (firmware->magic[2] != 'F') || (firmware->version != 1)) {
+               printk(KERN_ERR "QE: invalid or unsupported microcode\n");
+               return -EPERM;
+       }
+
+       /* Validate the length and check if there's a CRC */
+       for (i = 0; i < firmware->count; i++)
+               length += firmware->microcode[i].count * 4;
+
+       if (firmware->length == (length + sizeof(u32))) {
+               /* Length is valid, and there's a CRC */
+               crc = be32_to_cpu(*((__be32 *) ((void *) firmware + length)));
+               if (crc != crc32(0, firmware, length)) {
+                       printk(KERN_ERR "QE: firmware CRC is invalid\n");
+                       return -EIO;
+               }
+       } else if (firmware->length != length) {
+               printk(KERN_ERR "QE: invalid length(s) in firware structure\n");
+               return -EPERM;
+       }
+
+       /* If there's only one microcode, then we assume it's common for all
+          RISCs, so we set the CERCR.CIR bit to share the IRAM with all RISCs.
+          This should be safe even on SOCs with only one RISC.
+
+          If there are multiple 'microcode' structures, but each one points
+          to the same microcode binary (ignoring offsets), then we also assume
+          that we want share RAM.
+        */
+       if (firmware->count == 1)
+             setbits16(&qe_immr->cp.cercr, cpu_to_be16(0x800));
+       else {
+               for (i = 1; i < firmware->count; i++)
+                       if (firmware->microcode[i].code_offset !=
+                           firmware->microcode[0].code_offset)
+                               break;
+
+               if (i == firmware->count)
+                       setbits16(&qe_immr->cp.cercr, cpu_to_be16(0x800));
+       }
+
+       if (firmware->soc.model)
+               printk(KERN_INFO "QE: uploading microcode '%s' for %u V%u.%u\n",
+                       firmware->id, be16_to_cpu(firmware->soc.model),
+                       firmware->soc.rev_h, firmware->soc.rev_l);
+       else
+               printk(KERN_INFO "QE: uploading microcode '%s'\n",
+                       firmware->id);
+
+       for (i = 0; i < firmware->count; i++) {
+               const struct qe_microcode *ucode = &firmware->microcode[i];
+
+               code = (void *) firmware + be32_to_cpu(ucode->code_offset);
+
+               /* Use auto-increment */
+               out_be32(&qe_immr->iram.iadd, cpu_to_be32(0x80080000 |
+                       be32_to_cpu(ucode->iram_offset)));
+
+               for (j = 0; j < ucode->count; j++)
+                       out_be32(&qe_immr->iram.idata, be32_to_cpu(code[j]));
+
+               /* Program the traps.  We program both RISCs, even on platforms
+                  that only have one.  This *should* be safe. */
+               for (j = 0; j < 16; j++)
+                       if (ucode->traps[j]) {
+                               u32 trap = be32_to_cpu(ucode->traps[j]);
+                               out_be32(&qe_immr->rsp[0].tibcr[j], trap);
+                               out_be32(&qe_immr->rsp[1].tibcr[j], trap);
+                       }
+       }
+
+       /* Enable the traps for both RISCs.  Again, on a single-RISC system,
+          this should be safe. */
+       out_be32(&qe_immr->rsp[0].eccr, cpu_to_be32(0x20800000));
+       out_be32(&qe_immr->rsp[1].eccr, cpu_to_be32(0x20800000));
+
+       return 0;
+}
+EXPORT_SYMBOL(qe_upload_microcode);
diff --git a/include/asm-powerpc/immap_qe.h b/include/asm-powerpc/immap_qe.h
index aba9806..d0c60c4 100644
--- a/include/asm-powerpc/immap_qe.h
+++ b/include/asm-powerpc/immap_qe.h
@@ -395,8 +395,33 @@ struct dbg {
 
 /* RISC Special Registers (Trap and Breakpoint) */
 struct rsp {
-       u32     reg[0x40];      /* 64 32-bit registers */
-} __attribute__ ((packed));
+       __be32 tibcr[16];
+       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;
+       u8 res3[24];
+       __be32 eccr;
+       __be32 eicr;
+       u8 res4[0x100-0xf8];
+};
 
 struct qe_immap {
        struct qe_iram          iram;           /* I-RAM */
diff --git a/include/asm-powerpc/qe.h b/include/asm-powerpc/qe.h
index 81403ee..f773280 100644
--- a/include/asm-powerpc/qe.h
+++ b/include/asm-powerpc/qe.h
@@ -94,6 +94,134 @@ unsigned long qe_muram_alloc_fixed(unsigned long offset, 
int size);
 void qe_muram_dump(void);
 void *qe_muram_addr(unsigned long offset);
 
+/* Structure that defines QE firmware binary files.
+ *
+ * All integers are big-endian.  All lengths are in bytes.
+ *
+ * The 'length' field is the size, in bytes, of the entire structure,
+ * including all the microcode embedded in it, as well as the CRC (if
+ * present).
+ *
+ * The 'magic' field is an array of three bytes that contains the letters
+ * 'Q', 'E', and 'F'.  This is an identifier that indicates that this
+ * structure is a QE Firmware structure.
+ *
+ * The 'version' field is a single byte that indicates the version of this
+ * structure.  If the layout of the structure should ever need to be changed
+ * to add support for additional types of microcode, then the version number
+ * should also be changed.  Currently, only version 1 (this version) is
+ * supported, so this field must be set to 1.
+ *
+ * The 'id' field is a null-terminated string suitable for printing.
+ *
+ * The 'count' field indicates the number of 'microcode' structures.  If
+ * there are multiple RISC processors, then it's possible to have a
+ * different microcode for each one.  This allows for three possible
+ * scenarios:
+ *
+ *      1) Single microcode common to all RISCs
+ *      2) Single microcode copied to multiple offsets, one per RISC
+ *      3) Different microcode and traps for each RISC
+ *
+ * In scenarious (1) and (2), the CERCR.CIR bit is set to 1, which allows
+ * all of IRAM to be shared among all RISC processors.
+ *
+ * The 'soc' structure contains the SOC numbers and revisions used to match
+ * the microcode to the SOC itself.  Normally, the microcode loader should
+ * check the data in this structure with the SOC number and revisions, and
+ * only upload the microcode if there's a match.  However, because there is
+ * no generic way to obtain the SOC model and revision, this check is not
+ * currently made.
+ *
+ * Although it is not recommended, you can specify '0' in the soc.model
+ * field to skip matching SOCs altogether.
+ *
+ * The 'model' field is a 16-bit number that matches the actual SOC. The
+ * 'rev_h' and 'rev_l' fields match the high and low bytes of the SOC
+ * revision ID.
+ *
+ * For example, to match the 8323, revision 1.0:
+ *      soc.model = 8323
+ *      soc.rev_h = 1
+ *      soc.rev_h = 0
+ *
+ * 'reserved' is neccessary for structure alignment.  This field ensures
+ * that the first element of the 'microcode' array is aligned on a 64-bit
+ * boundary.
+ *
+ * 'microcode' (type: struct qe_microcode):
+ *      'traps' is an array of 16 words that contain hardware trap values
+ *      for each of the 16 traps.  If trap[i] is 0, then this particular
+ *      trap is to be ignored (i.e. not written to TIBCR[i]).
+ *
+ *      'vtraps' is an array of 8 words that contain virtual trap values for
+ *      each virtual traps.  Currently, this field is ignored.
+ *
+ *      'extended_modes' is a bitfield that defines special functionality
+ *      which has an impact on the software drivers.  Each bit has its own
+ *      impact and has special instructions for the driver associated with
+ *      it.  Currently, this field is ignored.
+ *
+ *      'iram_offset' is the offset into IRAM to start writing the
+ *      microcode.
+ *
+ *      'count' is the number of 32-bit words in the microcode.
+ *
+ *      'code_offset' is the offset, in bytes, from the beginning of this
+ *      structure where the microcode itself can be found.  The first
+ *      microcode binary should be located immediately after the 'microcode'
+ *      array.
+ *
+ *      'reserved' is necessary for structure alignment.  Since 'microcode'
+ *      is an array, the 64-bit 'extended_modes' field needs to be aligned
+ *      on a 64-bit boundary, and this can only happen if the size of
+ *      'microcode' is a multiple of 8 bytes.  To ensure that, we add
+ *      'reserved'.
+ *
+ * In addition, an optional 32-bit CRC can be added after the last
+ * microcode binary.  The CRC is checked via the crc32() Linux kernel macro.
+ * It can be calculated using this algorithm:
+ *
+ * u32 crc32(const u8 *p, unsigned int len)
+ * {
+ *         unsigned int i;
+ *         u32 crc = 0;
+ *
+ *         while (len--) {
+ *                crc ^= *p++;
+ *                for (i = 0; i < 8; i++)
+ *                        crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
+ *         }
+ *         return crc;
+ * }
+ */
+struct qe_firmware {
+       __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' */
+       u8 id[63];      /* Null-terminated identifier string */
+       u8 count;       /* Number of microcode[] structures */
+       struct {
+               __be16 model;           /* The SOC model  */
+               u8 rev_h;               /* The SOC revision */
+               u8 rev_l;               /* The SOC revision */
+       } soc;
+       __be32 reserved;                /* Reserved, for alignement */
+       struct qe_microcode {
+               __be32 traps[16];       /* Trap addresses, 0 == ignore */
+               __be32 vtraps[8];       /* Virtual trap addresses */
+               __be64 extended_modes;  /* Extended modes */
+               __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 */
+               __be32 reserved;        /* Reserved, for alignement */
+       } microcode[1];                 /* At least one microcode */
+       /* All microcode binaries should be located here */
+       /* An optional CRC32 can be added after the microcode binaries here */
+} __attribute__ ((packed));
+
+int qe_upload_microcode(const struct qe_firmware *firmware);
+
 /* Buffer descriptors */
 struct qe_bd {
        __be16 status;
-- 
1.5.2.4

_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-dev

Reply via email to