Until now, the inside-secure driver required a set of firmware images to be
present in /lib/firmware/inside-secure in order to be able to function.
These firmware images were not available to the general public and diffi-
cult to obtain (only under NDA from Marvell). Also, the driver did and does
not use any specific firmware functionality. This patch removes the depen-
dence on those firmware images.

Signed-off-by: Pascal van Leeuwen <pvanleeu...@insidesecure.com>
---
 drivers/crypto/inside-secure/safexcel.c | 217 +++++++++++++++++++++++++-------
 drivers/crypto/inside-secure/safexcel.h |   6 +
 2 files changed, 180 insertions(+), 43 deletions(-)

diff --git a/drivers/crypto/inside-secure/safexcel.c 
b/drivers/crypto/inside-secure/safexcel.c
index a6a0f48..e1781b2 100644
--- a/drivers/crypto/inside-secure/safexcel.c
+++ b/drivers/crypto/inside-secure/safexcel.c
@@ -107,44 +107,160 @@ static void eip197_trc_cache_init(struct 
safexcel_crypto_priv *priv)
        writel(val, priv->base + EIP197_TRC_PARAMS);
 }
 
-static void eip197_write_firmware(struct safexcel_crypto_priv *priv,
-                                 const struct firmware *fw, int pe, u32 ctrl,
-                                 u32 prog_en)
+static void eip197_init_firmware(struct safexcel_crypto_priv *priv)
 {
-       const u32 *data = (const u32 *)fw->data;
+       int pe, i;
        u32 val;
-       int i;
 
-       /* Reset the engine to make its program memory accessible */
-       writel(EIP197_PE_ICE_x_CTRL_SW_RESET |
-              EIP197_PE_ICE_x_CTRL_CLR_ECC_CORR |
-              EIP197_PE_ICE_x_CTRL_CLR_ECC_NON_CORR,
-              EIP197_PE(priv) + ctrl);
+       for (pe = 0; pe < priv->config.pes; pe++) {
+               /* Configure the token FIFO's */
+               writel(3, EIP197_PE(priv) + EIP197_PE_ICE_PUTF_CTRL(pe));
+               writel(0, EIP197_PE(priv) + EIP197_PE_ICE_PPTF_CTRL(pe));
+
+               /* Clear the ICE scratchpad memory */
+               val = readl(EIP197_PE(priv) + EIP197_PE_ICE_SCRATCH_CTRL(pe));
+               val |= EIP197_PE_ICE_SCRATCH_CTRL_CHANGE_TIMER |
+                      EIP197_PE_ICE_SCRATCH_CTRL_TIMER_EN |
+                      EIP197_PE_ICE_SCRATCH_CTRL_SCRATCH_ACCESS |
+                      EIP197_PE_ICE_SCRATCH_CTRL_CHANGE_ACCESS;
+               writel(val, EIP197_PE(priv) + EIP197_PE_ICE_SCRATCH_CTRL(pe));
+
+               /* clear the scratchpad RAM using 32 bit writes only */
+               for (i = 0; i < EIP197_NUM_OF_SCRATCH_BLOCKS; i++)
+                       writel(0, EIP197_PE(priv) +
+                                 EIP197_PE_ICE_SCRATCH_RAM(pe) + (i<<2));
+
+               /* Reset the IFPP engine to make its program mem accessible */
+               writel(EIP197_PE_ICE_x_CTRL_SW_RESET |
+                      EIP197_PE_ICE_x_CTRL_CLR_ECC_CORR |
+                      EIP197_PE_ICE_x_CTRL_CLR_ECC_NON_CORR,
+                      EIP197_PE(priv) + EIP197_PE_ICE_FPP_CTRL(pe));
+
+               /* Reset the IPUE engine to make its program mem accessible */
+               writel(EIP197_PE_ICE_x_CTRL_SW_RESET |
+                      EIP197_PE_ICE_x_CTRL_CLR_ECC_CORR |
+                      EIP197_PE_ICE_x_CTRL_CLR_ECC_NON_CORR,
+                      EIP197_PE(priv) + EIP197_PE_ICE_PUE_CTRL(pe));
+
+               /* Enable access to all IFPP program memories */
+               writel(EIP197_PE_ICE_RAM_CTRL_FPP_PROG_EN,
+                      EIP197_PE(priv) + EIP197_PE_ICE_RAM_CTRL(pe));
+       }
+
+}
 
-       /* Enable access to the program memory */
-       writel(prog_en, EIP197_PE(priv) + EIP197_PE_ICE_RAM_CTRL(pe));
+static int eip197_write_firmware(struct safexcel_crypto_priv *priv,
+                                 const struct firmware *fw)
+{
+       const u32 *data = (const u32 *)fw->data;
+       int i;
 
        /* Write the firmware */
        for (i = 0; i < fw->size / sizeof(u32); i++)
                writel(be32_to_cpu(data[i]),
                       priv->base + EIP197_CLASSIFICATION_RAMS + i * 
sizeof(u32));
 
-       /* Disable access to the program memory */
-       writel(0, EIP197_PE(priv) + EIP197_PE_ICE_RAM_CTRL(pe));
+       return i - 2;
+}
+
+/*
+ * If FW is actual production firmware, then poll for its initialization
+ * to complete and check if it is good for the HW, otherwise just return OK.
+ */
+static bool poll_fw_ready(struct safexcel_crypto_priv *priv, int fpp)
+{
+       int pe, pollcnt;
+       u32 base, pollofs;
+
+       if (fpp)
+               pollofs  = EIP197_FW_FPP_READY;
+       else
+               pollofs  = EIP197_FW_PUE_READY;
+
+       for (pe = 0; pe < priv->config.pes; pe++) {
+               base = EIP197_PE_ICE_SCRATCH_RAM(pe);
+               pollcnt = EIP197_FW_START_POLLCNT;
+               while (pollcnt &&
+                      (readl(EIP197_PE(priv) + base +
+                             pollofs) != 1)) {
+                       pollcnt--;
+                       cpu_relax();
+               }
+               if (!pollcnt) {
+                       dev_err(priv->dev, "FW(%d) for PE %d failed to start",
+                               fpp, pe);
+                       return false;
+               }
+       }
+       return true;
+}
+
+static bool eip197_start_firmware(struct safexcel_crypto_priv *priv,
+                                 int ipuesz, int ifppsz)
+{
+       int pe;
+       u32 val;
+
+       for (pe = 0; pe < priv->config.pes; pe++) {
+               /* Disable access to all program memory */
+               writel(0, EIP197_PE(priv) + EIP197_PE_ICE_RAM_CTRL(pe));
+
+               /* Start IFPP microengines */
+               if (ifppsz)
+                       val = (((ifppsz - 1) & 0x7ff0) << 16) | BIT(3);
+               else
+                       val = 0;
+               writel(val, EIP197_PE(priv) + EIP197_PE_ICE_FPP_CTRL(pe));
+
+               /* Start IPUE microengines */
+               if (ipuesz)
+                       val = ((ipuesz - 1) & 0x7ff0) << 16 | BIT(3);
+               else
+                       val = 0;
+               writel(val, EIP197_PE(priv) + EIP197_PE_ICE_PUE_CTRL(pe));
+       }
+
+       /* For miniFW startup, there is no initialization, so always succeed */
+       if ((!ipuesz) && (!ifppsz))
+               return true;
+
+       /* Wait until all the firmwares have properly started up */
+       if (!poll_fw_ready(priv, 1))
+               return false;
+       if (!poll_fw_ready(priv, 0))
+               return false;
 
-       /* Release engine from reset */
-       val = readl(EIP197_PE(priv) + ctrl);
-       val &= ~EIP197_PE_ICE_x_CTRL_SW_RESET;
-       writel(val, EIP197_PE(priv) + ctrl);
+       return true;
 }
 
 static int eip197_load_firmwares(struct safexcel_crypto_priv *priv)
 {
+       /*
+        * The embedded one-size-fits-all MiniFW is just for handling TR
+        * prefetch & invalidate. It does not support any FW flows, effectively
+        * turning the EIP197 into a glorified EIP97
+        */
+       const u32 ipue_minifw[] = {
+                0x24808200, 0x2D008204, 0x2680E208, 0x2780E20C,
+                0x2200F7FF, 0x38347000, 0x2300F000, 0x15200A80,
+                0x01699003, 0x60038011, 0x38B57000, 0x0119F04C,
+                0x01198548, 0x20E64000, 0x20E75000, 0x1E200000,
+                0x30E11000, 0x103A93FF, 0x60830014, 0x5B8B0000,
+                0xC0389000, 0x600B0018, 0x2300F000, 0x60800011,
+                0x90800000, 0x10000000, 0x10000000};
+       const u32 ifpp_minifw[] = {
+                0x21008000, 0x260087FC, 0xF01CE4C0, 0x60830006,
+                0x530E0000, 0x90800000, 0x23008004, 0x24808008,
+                0x2580800C, 0x0D300000, 0x205577FC, 0x30D42000,
+                0x20DAA7FC, 0x43107000, 0x42220004, 0x00000000,
+                0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                0x00060004, 0x20337004, 0x90800000, 0x10000000,
+                0x10000000};
        const char *fw_name[] = {"ifpp.bin", "ipue.bin"};
        const struct firmware *fw[FW_NB];
        char fw_path[31], *dir = NULL;
        int i, j, ret = 0, pe;
-       u32 val;
+       int ipuesz, ifppsz;
 
        if (priv->version & EIP197B)
                dir = "eip197b";
@@ -156,7 +272,7 @@ static int eip197_load_firmwares(struct 
safexcel_crypto_priv *priv)
 
        for (i = 0; i < FW_NB; i++) {
                snprintf(fw_path, 31, "inside-secure/%s/%s", dir, fw_name[i]);
-               ret = request_firmware(&fw[i], fw_path, priv->dev);
+               ret = firmware_request_nowarn(&fw[i], fw_path, priv->dev);
                if (ret) {
                        if (!(priv->version & EIP197B))
                                goto release_fw;
@@ -164,42 +280,57 @@ static int eip197_load_firmwares(struct 
safexcel_crypto_priv *priv)
                        /* Fallback to the old firmware location for the
                         * EIP197b.
                         */
-                       ret = request_firmware(&fw[i], fw_name[i], priv->dev);
-                       if (ret) {
-                               dev_err(priv->dev,
-                                       "Failed to request firmware %s (%d)\n",
-                                       fw_name[i], ret);
+                       ret = firmware_request_nowarn(&fw[i], fw_name[i],
+                                                     priv->dev);
+                       if (ret)
                                goto release_fw;
-                       }
                }
        }
 
-       for (pe = 0; pe < priv->config.pes; pe++) {
-               /* Clear the scratchpad memory */
-               val = readl(EIP197_PE(priv) + EIP197_PE_ICE_SCRATCH_CTRL(pe));
-               val |= EIP197_PE_ICE_SCRATCH_CTRL_CHANGE_TIMER |
-                      EIP197_PE_ICE_SCRATCH_CTRL_TIMER_EN |
-                      EIP197_PE_ICE_SCRATCH_CTRL_SCRATCH_ACCESS |
-                      EIP197_PE_ICE_SCRATCH_CTRL_CHANGE_ACCESS;
-               writel(val, EIP197_PE(priv) + EIP197_PE_ICE_SCRATCH_CTRL(pe));
+       eip197_init_firmware(priv);
+
+       ifppsz = eip197_write_firmware(priv, fw[FW_IFPP]);
 
-               memset_io(EIP197_PE(priv) + EIP197_PE_ICE_SCRATCH_RAM(pe), 0,
-                         EIP197_NUM_OF_SCRATCH_BLOCKS * sizeof(u32));
+       /* Enable access to IPUE program memories */
+       for (pe = 0; pe < priv->config.pes; pe++)
+               writel(EIP197_PE_ICE_RAM_CTRL_PUE_PROG_EN,
+                      EIP197_PE(priv) + EIP197_PE_ICE_RAM_CTRL(pe));
 
-               eip197_write_firmware(priv, fw[FW_IFPP], pe,
-                                     EIP197_PE_ICE_FPP_CTRL(pe),
-                                     EIP197_PE_ICE_RAM_CTRL_FPP_PROG_EN);
+       ipuesz = eip197_write_firmware(priv, fw[FW_IPUE]);
 
-               eip197_write_firmware(priv, fw[FW_IPUE], pe,
-                                     EIP197_PE_ICE_PUE_CTRL(pe),
-                                     EIP197_PE_ICE_RAM_CTRL_PUE_PROG_EN);
+       if (eip197_start_firmware(priv, ipuesz, ifppsz)) {
+               dev_info(priv->dev, "EIP197 firmware loaded successfully");
+               return 0;
        }
 
 release_fw:
        for (j = 0; j < i; j++)
                release_firmware(fw[j]);
 
-       return ret;
+       /*
+        * Firmware download failed, fall back to EIP97 BCLA mode
+        * Note that this is not a formally supported mode for the EIP197,
+        * so your mileage may vary
+        */
+       dev_info(priv->dev, "EIP197 firmware set not (fully) present or init 
failed, falling back to EIP97 BCLA mode");
+
+       eip197_init_firmware(priv);
+
+       for (i = 0; i < sizeof(ifpp_minifw)>>2; i++)
+               writel(ifpp_minifw[i],
+                      priv->base + EIP197_CLASSIFICATION_RAMS + (i<<2));
+
+       /* Enable access to IPUE program memories */
+       for (pe = 0; pe < priv->config.pes; pe++)
+               writel(EIP197_PE_ICE_RAM_CTRL_PUE_PROG_EN,
+                      EIP197_PE(priv) + EIP197_PE_ICE_RAM_CTRL(pe));
+
+       for (i = 0; i < sizeof(ipue_minifw)>>2; i++)
+               writel(ipue_minifw[i],
+                      priv->base + EIP197_CLASSIFICATION_RAMS + (i<<2));
+
+       eip197_start_firmware(priv, 0, 0);
+       return 0;
 }
 
 static int safexcel_hw_setup_cdesc_rings(struct safexcel_crypto_priv *priv)
diff --git a/drivers/crypto/inside-secure/safexcel.h 
b/drivers/crypto/inside-secure/safexcel.h
index 924270e..380ba72 100644
--- a/drivers/crypto/inside-secure/safexcel.h
+++ b/drivers/crypto/inside-secure/safexcel.h
@@ -128,8 +128,10 @@
 #define EIP197_PE_IN_TBUF_THRES(n)             (0x0100 + (0x2000 * (n)))
 #define EIP197_PE_ICE_SCRATCH_RAM(n)           (0x0800 + (0x2000 * (n)))
 #define EIP197_PE_ICE_PUE_CTRL(n)              (0x0c80 + (0x2000 * (n)))
+#define EIP197_PE_ICE_PUTF_CTRL(n)             (0x0d00 + (0x2000 * (n)))
 #define EIP197_PE_ICE_SCRATCH_CTRL(n)          (0x0d04 + (0x2000 * (n)))
 #define EIP197_PE_ICE_FPP_CTRL(n)              (0x0d80 + (0x2000 * (n)))
+#define EIP197_PE_ICE_PPTF_CTRL(n)             (0x0e00 + (0x2000 * (n)))
 #define EIP197_PE_ICE_RAM_CTRL(n)              (0x0ff0 + (0x2000 * (n)))
 #define EIP197_PE_EIP96_TOKEN_CTRL(n)          (0x1000 + (0x2000 * (n)))
 #define EIP197_PE_EIP96_FUNCTION_EN(n)         (0x1004 + (0x2000 * (n)))
@@ -522,6 +524,10 @@ struct safexcel_command_desc {
  * Internal structures & functions
  */
 
+#define EIP197_FW_START_POLLCNT                16
+#define EIP197_FW_PUE_READY             0x14
+#define EIP197_FW_FPP_READY             0x18
+
 enum eip197_fw {
        FW_IFPP = 0,
        FW_IPUE,
-- 
1.8.3.1

Reply via email to