|
@@ -2,13 +2,15 @@
|
|
|
* CAAM control-plane driver backend
|
|
|
* Controller-level driver, kernel property detection, initialization
|
|
|
*
|
|
|
- * Copyright 2008-2011 Freescale Semiconductor, Inc.
|
|
|
+ * Copyright 2008-2012 Freescale Semiconductor, Inc.
|
|
|
*/
|
|
|
|
|
|
#include "compat.h"
|
|
|
#include "regs.h"
|
|
|
#include "intern.h"
|
|
|
#include "jr.h"
|
|
|
+#include "desc_constr.h"
|
|
|
+#include "error.h"
|
|
|
|
|
|
static int caam_remove(struct platform_device *pdev)
|
|
|
{
|
|
@@ -43,10 +45,120 @@ static int caam_remove(struct platform_device *pdev)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Descriptor to instantiate RNG State Handle 0 in normal mode and
|
|
|
+ * load the JDKEK, TDKEK and TDSK registers
|
|
|
+ */
|
|
|
+static void build_instantiation_desc(u32 *desc)
|
|
|
+{
|
|
|
+ u32 *jump_cmd;
|
|
|
+
|
|
|
+ init_job_desc(desc, 0);
|
|
|
+
|
|
|
+ /* INIT RNG in non-test mode */
|
|
|
+ append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG |
|
|
|
+ OP_ALG_AS_INIT);
|
|
|
+
|
|
|
+ /* wait for done */
|
|
|
+ jump_cmd = append_jump(desc, JUMP_CLASS_CLASS1);
|
|
|
+ set_jump_tgt_here(desc, jump_cmd);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * load 1 to clear written reg:
|
|
|
+ * resets the done interrrupt and returns the RNG to idle.
|
|
|
+ */
|
|
|
+ append_load_imm_u32(desc, 1, LDST_SRCDST_WORD_CLRW);
|
|
|
+
|
|
|
+ /* generate secure keys (non-test) */
|
|
|
+ append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG |
|
|
|
+ OP_ALG_RNG4_SK);
|
|
|
+}
|
|
|
+
|
|
|
+struct instantiate_result {
|
|
|
+ struct completion completion;
|
|
|
+ int err;
|
|
|
+};
|
|
|
+
|
|
|
+static void rng4_init_done(struct device *dev, u32 *desc, u32 err,
|
|
|
+ void *context)
|
|
|
+{
|
|
|
+ struct instantiate_result *instantiation = context;
|
|
|
+
|
|
|
+ if (err) {
|
|
|
+ char tmp[CAAM_ERROR_STR_MAX];
|
|
|
+
|
|
|
+ dev_err(dev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err));
|
|
|
+ }
|
|
|
+
|
|
|
+ instantiation->err = err;
|
|
|
+ complete(&instantiation->completion);
|
|
|
+}
|
|
|
+
|
|
|
+static int instantiate_rng(struct device *jrdev)
|
|
|
+{
|
|
|
+ struct instantiate_result instantiation;
|
|
|
+
|
|
|
+ dma_addr_t desc_dma;
|
|
|
+ u32 *desc;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ desc = kmalloc(CAAM_CMD_SZ * 6, GFP_KERNEL | GFP_DMA);
|
|
|
+ if (!desc) {
|
|
|
+ dev_err(jrdev, "cannot allocate RNG init descriptor memory\n");
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+
|
|
|
+ build_instantiation_desc(desc);
|
|
|
+ desc_dma = dma_map_single(jrdev, desc, desc_bytes(desc), DMA_TO_DEVICE);
|
|
|
+ init_completion(&instantiation.completion);
|
|
|
+ ret = caam_jr_enqueue(jrdev, desc, rng4_init_done, &instantiation);
|
|
|
+ if (!ret) {
|
|
|
+ wait_for_completion_interruptible(&instantiation.completion);
|
|
|
+ ret = instantiation.err;
|
|
|
+ if (ret)
|
|
|
+ dev_err(jrdev, "unable to instantiate RNG\n");
|
|
|
+ }
|
|
|
+
|
|
|
+ dma_unmap_single(jrdev, desc_dma, desc_bytes(desc), DMA_TO_DEVICE);
|
|
|
+
|
|
|
+ kfree(desc);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * By default, the TRNG runs for 200 clocks per sample;
|
|
|
+ * 800 clocks per sample generates better entropy.
|
|
|
+ */
|
|
|
+static void kick_trng(struct platform_device *pdev)
|
|
|
+{
|
|
|
+ struct device *ctrldev = &pdev->dev;
|
|
|
+ struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev);
|
|
|
+ struct caam_full __iomem *topregs;
|
|
|
+ struct rng4tst __iomem *r4tst;
|
|
|
+ u32 val;
|
|
|
+
|
|
|
+ topregs = (struct caam_full __iomem *)ctrlpriv->ctrl;
|
|
|
+ r4tst = &topregs->ctrl.r4tst[0];
|
|
|
+
|
|
|
+ /* put RNG4 into program mode */
|
|
|
+ setbits32(&r4tst->rtmctl, RTMCTL_PRGM);
|
|
|
+ /* 800 clocks per sample */
|
|
|
+ val = rd_reg32(&r4tst->rtsdctl);
|
|
|
+ val = (val & ~RTSDCTL_ENT_DLY_MASK) | (800 << RTSDCTL_ENT_DLY_SHIFT);
|
|
|
+ wr_reg32(&r4tst->rtsdctl, val);
|
|
|
+ /* min. freq. count */
|
|
|
+ wr_reg32(&r4tst->rtfrqmin, 400);
|
|
|
+ /* max. freq. count */
|
|
|
+ wr_reg32(&r4tst->rtfrqmax, 6400);
|
|
|
+ /* put RNG4 into run mode */
|
|
|
+ clrbits32(&r4tst->rtmctl, RTMCTL_PRGM);
|
|
|
+}
|
|
|
+
|
|
|
/* Probe routine for CAAM top (controller) level */
|
|
|
static int caam_probe(struct platform_device *pdev)
|
|
|
{
|
|
|
- int ring, rspec;
|
|
|
+ int ret, ring, rspec;
|
|
|
struct device *dev;
|
|
|
struct device_node *nprop, *np;
|
|
|
struct caam_ctrl __iomem *ctrl;
|
|
@@ -146,6 +258,19 @@ static int caam_probe(struct platform_device *pdev)
|
|
|
return -ENOMEM;
|
|
|
}
|
|
|
|
|
|
+ /*
|
|
|
+ * RNG4 based SECs (v5+) need special initialization prior
|
|
|
+ * to executing any descriptors
|
|
|
+ */
|
|
|
+ if (of_device_is_compatible(nprop, "fsl,sec-v5.0")) {
|
|
|
+ kick_trng(pdev);
|
|
|
+ ret = instantiate_rng(ctrlpriv->jrdev[0]);
|
|
|
+ if (ret) {
|
|
|
+ caam_remove(pdev);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/* NOTE: RTIC detection ought to go here, around Si time */
|
|
|
|
|
|
/* Initialize queue allocator lock */
|