Commit 281922a1 authored by Kim Phillips's avatar Kim Phillips Committed by Herbert Xu

crypto: caam - add support for SEC v5.x RNG4

The SEC v4.x' RNGB h/w block self-initialized.  RNG4, available
on SEC versions 5 and beyond, is based on a different standard
that requires manual initialization.

Also update any new errors From the SEC v5.2 reference manual:
The SEC v5.2's RNG4 unit reuses some error IDs, thus the addition
of rng_err_id_list over the CHA-independent err_id_list.
Signed-off-by: default avatarKim Phillips <kim.phillips@freescale.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent e13af18a
...@@ -2,13 +2,15 @@ ...@@ -2,13 +2,15 @@
* CAAM control-plane driver backend * CAAM control-plane driver backend
* Controller-level driver, kernel property detection, initialization * Controller-level driver, kernel property detection, initialization
* *
* Copyright 2008-2011 Freescale Semiconductor, Inc. * Copyright 2008-2012 Freescale Semiconductor, Inc.
*/ */
#include "compat.h" #include "compat.h"
#include "regs.h" #include "regs.h"
#include "intern.h" #include "intern.h"
#include "jr.h" #include "jr.h"
#include "desc_constr.h"
#include "error.h"
static int caam_remove(struct platform_device *pdev) static int caam_remove(struct platform_device *pdev)
{ {
...@@ -43,10 +45,120 @@ static int caam_remove(struct platform_device *pdev) ...@@ -43,10 +45,120 @@ static int caam_remove(struct platform_device *pdev)
return ret; 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 */ /* Probe routine for CAAM top (controller) level */
static int caam_probe(struct platform_device *pdev) static int caam_probe(struct platform_device *pdev)
{ {
int ring, rspec; int ret, ring, rspec;
struct device *dev; struct device *dev;
struct device_node *nprop, *np; struct device_node *nprop, *np;
struct caam_ctrl __iomem *ctrl; struct caam_ctrl __iomem *ctrl;
...@@ -146,6 +258,19 @@ static int caam_probe(struct platform_device *pdev) ...@@ -146,6 +258,19 @@ static int caam_probe(struct platform_device *pdev)
return -ENOMEM; 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 */ /* NOTE: RTIC detection ought to go here, around Si time */
/* Initialize queue allocator lock */ /* Initialize queue allocator lock */
......
...@@ -1172,6 +1172,11 @@ struct sec4_sg_entry { ...@@ -1172,6 +1172,11 @@ struct sec4_sg_entry {
#define OP_ALG_AAI_GSM (0x10 << OP_ALG_AAI_SHIFT) #define OP_ALG_AAI_GSM (0x10 << OP_ALG_AAI_SHIFT)
#define OP_ALG_AAI_EDGE (0x20 << OP_ALG_AAI_SHIFT) #define OP_ALG_AAI_EDGE (0x20 << OP_ALG_AAI_SHIFT)
/* RNG4 set */
#define OP_ALG_RNG4_SHIFT 4
#define OP_ALG_RNG4_MASK (0x1f3 << OP_ALG_RNG4_SHIFT)
#define OP_ALG_RNG4_SK (0x100 << OP_ALG_RNG4_SHIFT)
#define OP_ALG_AS_SHIFT 2 #define OP_ALG_AS_SHIFT 2
#define OP_ALG_AS_MASK (0x3 << OP_ALG_AS_SHIFT) #define OP_ALG_AS_MASK (0x3 << OP_ALG_AS_SHIFT)
......
...@@ -39,18 +39,20 @@ static void report_ccb_status(u32 status, char *outstr) ...@@ -39,18 +39,20 @@ static void report_ccb_status(u32 status, char *outstr)
char *cha_id_list[] = { char *cha_id_list[] = {
"", "",
"AES", "AES",
"DES, 3DES", "DES",
"ARC4", "ARC4",
"MD5, SHA-1, SH-224, SHA-256, SHA-384, SHA-512", "MDHA",
"RNG", "RNG",
"SNOW f8", "SNOW f8",
"Kasumi f8, f9", "Kasumi f8/9",
"All Public Key Algorithms", "PKHA",
"CRC", "CRCA",
"SNOW f9", "SNOW f9",
"ZUCE",
"ZUCA",
}; };
char *err_id_list[] = { char *err_id_list[] = {
"None. No error.", "No error.",
"Mode error.", "Mode error.",
"Data size error.", "Data size error.",
"Key size error.", "Key size error.",
...@@ -67,6 +69,20 @@ static void report_ccb_status(u32 status, char *outstr) ...@@ -67,6 +69,20 @@ static void report_ccb_status(u32 status, char *outstr)
"Invalid CHA combination was selected", "Invalid CHA combination was selected",
"Invalid CHA selected.", "Invalid CHA selected.",
}; };
char *rng_err_id_list[] = {
"",
"",
"",
"Instantiate",
"Not instantiated",
"Test instantiate",
"Prediction resistance",
"",
"Prediction resistance and test request",
"Uninstantiate",
"",
"Secure key generation",
};
u8 cha_id = (status & JRSTA_CCBERR_CHAID_MASK) >> u8 cha_id = (status & JRSTA_CCBERR_CHAID_MASK) >>
JRSTA_CCBERR_CHAID_SHIFT; JRSTA_CCBERR_CHAID_SHIFT;
u8 err_id = status & JRSTA_CCBERR_ERRID_MASK; u8 err_id = status & JRSTA_CCBERR_ERRID_MASK;
...@@ -81,7 +97,13 @@ static void report_ccb_status(u32 status, char *outstr) ...@@ -81,7 +97,13 @@ static void report_ccb_status(u32 status, char *outstr)
cha_id, sizeof("ff")); cha_id, sizeof("ff"));
} }
if (err_id < ARRAY_SIZE(err_id_list)) { if ((cha_id << JRSTA_CCBERR_CHAID_SHIFT) == JRSTA_CCBERR_CHAID_RNG &&
err_id < ARRAY_SIZE(rng_err_id_list) &&
strlen(rng_err_id_list[err_id])) {
/* RNG-only error */
SPRINTFCAT(outstr, "%s", rng_err_id_list[err_id],
strlen(rng_err_id_list[err_id]));
} else if (err_id < ARRAY_SIZE(err_id_list)) {
SPRINTFCAT(outstr, "%s", err_id_list[err_id], SPRINTFCAT(outstr, "%s", err_id_list[err_id],
strlen(err_id_list[err_id])); strlen(err_id_list[err_id]));
} else { } else {
...@@ -101,10 +123,10 @@ static void report_deco_status(u32 status, char *outstr) ...@@ -101,10 +123,10 @@ static void report_deco_status(u32 status, char *outstr)
u8 value; u8 value;
char *error_text; char *error_text;
} desc_error_list[] = { } desc_error_list[] = {
{ 0x00, "None. No error." }, { 0x00, "No error." },
{ 0x01, "SGT Length Error. The descriptor is trying to read " { 0x01, "SGT Length Error. The descriptor is trying to read "
"more data than is contained in the SGT table." }, "more data than is contained in the SGT table." },
{ 0x02, "Reserved." }, { 0x02, "SGT Null Entry Error." },
{ 0x03, "Job Ring Control Error. There is a bad value in the " { 0x03, "Job Ring Control Error. There is a bad value in the "
"Job Ring Control register." }, "Job Ring Control register." },
{ 0x04, "Invalid Descriptor Command. The Descriptor Command " { 0x04, "Invalid Descriptor Command. The Descriptor Command "
...@@ -116,7 +138,7 @@ static void report_deco_status(u32 status, char *outstr) ...@@ -116,7 +138,7 @@ static void report_deco_status(u32 status, char *outstr)
{ 0x09, "Invalid OPERATION Command" }, { 0x09, "Invalid OPERATION Command" },
{ 0x0A, "Invalid FIFO LOAD Command" }, { 0x0A, "Invalid FIFO LOAD Command" },
{ 0x0B, "Invalid FIFO STORE Command" }, { 0x0B, "Invalid FIFO STORE Command" },
{ 0x0C, "Invalid MOVE Command" }, { 0x0C, "Invalid MOVE/MOVE_LEN Command" },
{ 0x0D, "Invalid JUMP Command. A nonlocal JUMP Command is " { 0x0D, "Invalid JUMP Command. A nonlocal JUMP Command is "
"invalid because the target is not a Job Header " "invalid because the target is not a Job Header "
"Command, or the jump is from a Trusted Descriptor to " "Command, or the jump is from a Trusted Descriptor to "
...@@ -166,6 +188,8 @@ static void report_deco_status(u32 status, char *outstr) ...@@ -166,6 +188,8 @@ static void report_deco_status(u32 status, char *outstr)
"(input frame; block ciphers) and IPsec decap (output " "(input frame; block ciphers) and IPsec decap (output "
"frame, when doing the next header byte update) and " "frame, when doing the next header byte update) and "
"DCRC (output frame)." }, "DCRC (output frame)." },
{ 0x23, "Read Input Frame error" },
{ 0x24, "JDKEK, TDKEK or TDSK not loaded error" },
{ 0x80, "DNR (do not run) error" }, { 0x80, "DNR (do not run) error" },
{ 0x81, "undefined protocol command" }, { 0x81, "undefined protocol command" },
{ 0x82, "invalid setting in PDB" }, { 0x82, "invalid setting in PDB" },
......
...@@ -167,7 +167,7 @@ struct partid { ...@@ -167,7 +167,7 @@ struct partid {
u32 pidr; /* partition ID, DECO */ u32 pidr; /* partition ID, DECO */
}; };
/* RNG test mode (replicated twice in some configurations) */ /* RNGB test mode (replicated twice in some configurations) */
/* Padded out to 0x100 */ /* Padded out to 0x100 */
struct rngtst { struct rngtst {
u32 mode; /* RTSTMODEx - Test mode */ u32 mode; /* RTSTMODEx - Test mode */
...@@ -200,6 +200,31 @@ struct rngtst { ...@@ -200,6 +200,31 @@ struct rngtst {
u32 rsvd14[15]; u32 rsvd14[15];
}; };
/* RNG4 TRNG test registers */
struct rng4tst {
#define RTMCTL_PRGM 0x00010000 /* 1 -> program mode, 0 -> run mode */
u32 rtmctl; /* misc. control register */
u32 rtscmisc; /* statistical check misc. register */
u32 rtpkrrng; /* poker range register */
union {
u32 rtpkrmax; /* PRGM=1: poker max. limit register */
u32 rtpkrsq; /* PRGM=0: poker square calc. result register */
};
#define RTSDCTL_ENT_DLY_SHIFT 16
#define RTSDCTL_ENT_DLY_MASK (0xffff << RTSDCTL_ENT_DLY_SHIFT)
u32 rtsdctl; /* seed control register */
union {
u32 rtsblim; /* PRGM=1: sparse bit limit register */
u32 rttotsam; /* PRGM=0: total samples register */
};
u32 rtfrqmin; /* frequency count min. limit register */
union {
u32 rtfrqmax; /* PRGM=1: freq. count max. limit register */
u32 rtfrqcnt; /* PRGM=0: freq. count register */
};
u32 rsvd1[56];
};
/* /*
* caam_ctrl - basic core configuration * caam_ctrl - basic core configuration
* starts base + 0x0000 padded out to 0x1000 * starts base + 0x0000 padded out to 0x1000
...@@ -249,7 +274,10 @@ struct caam_ctrl { ...@@ -249,7 +274,10 @@ struct caam_ctrl {
/* RNG Test/Verification/Debug Access 600-7ff */ /* RNG Test/Verification/Debug Access 600-7ff */
/* (Useful in Test/Debug modes only...) */ /* (Useful in Test/Debug modes only...) */
struct rngtst rtst[2]; union {
struct rngtst rtst[2];
struct rng4tst r4tst[2];
};
u32 rsvd9[448]; u32 rsvd9[448];
......
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