diff options
Diffstat (limited to 'drivers/crypto/fsl/jr.c')
-rw-r--r-- | drivers/crypto/fsl/jr.c | 127 |
1 files changed, 126 insertions, 1 deletions
diff --git a/drivers/crypto/fsl/jr.c b/drivers/crypto/fsl/jr.c index a107e6afcb..29681e18a6 100644 --- a/drivers/crypto/fsl/jr.c +++ b/drivers/crypto/fsl/jr.c @@ -10,6 +10,7 @@ #include <malloc.h> #include "fsl_sec.h" #include "jr.h" +#include "jobdesc.h" #define CIRC_CNT(head, tail, size) (((head) - (tail)) & (size - 1)) #define CIRC_SPACE(head, tail, size) CIRC_CNT((tail), (head) + 1, (size)) @@ -319,6 +320,120 @@ int sec_reset(void) return 0; } +static int instantiate_rng(void) +{ + struct result op; + u32 *desc; + u32 rdsta_val; + int ret = 0; + ccsr_sec_t __iomem *sec = + (ccsr_sec_t __iomem *)CONFIG_SYS_FSL_SEC_ADDR; + struct rng4tst __iomem *rng = + (struct rng4tst __iomem *)&sec->rng; + + memset(&op, 0, sizeof(struct result)); + + desc = malloc(sizeof(int) * 6); + if (!desc) { + printf("cannot allocate RNG init descriptor memory\n"); + return -1; + } + + inline_cnstr_jobdesc_rng_instantiation(desc); + ret = run_descriptor_jr(desc); + + if (ret) + printf("RNG: Instantiation failed with error %x\n", ret); + + rdsta_val = sec_in32(&rng->rdsta); + if (op.status || !(rdsta_val & RNG_STATE0_HANDLE_INSTANTIATED)) + return -1; + + return ret; +} + +static u8 get_rng_vid(void) +{ + ccsr_sec_t *sec = (void *)CONFIG_SYS_FSL_SEC_ADDR; + u32 cha_vid = sec_in32(&sec->chavid_ls); + + return (cha_vid & SEC_CHAVID_RNG_LS_MASK) >> SEC_CHAVID_LS_RNG_SHIFT; +} + +/* + * By default, the TRNG runs for 200 clocks per sample; + * 1200 clocks per sample generates better entropy. + */ +static void kick_trng(int ent_delay) +{ + ccsr_sec_t __iomem *sec = + (ccsr_sec_t __iomem *)CONFIG_SYS_FSL_SEC_ADDR; + struct rng4tst __iomem *rng = + (struct rng4tst __iomem *)&sec->rng; + u32 val; + + /* put RNG4 into program mode */ + sec_setbits32(&rng->rtmctl, RTMCTL_PRGM); + /* rtsdctl bits 0-15 contain "Entropy Delay, which defines the + * length (in system clocks) of each Entropy sample taken + * */ + val = sec_in32(&rng->rtsdctl); + val = (val & ~RTSDCTL_ENT_DLY_MASK) | + (ent_delay << RTSDCTL_ENT_DLY_SHIFT); + sec_out32(&rng->rtsdctl, val); + /* min. freq. count, equal to 1/4 of the entropy sample length */ + sec_out32(&rng->rtfreqmin, ent_delay >> 2); + /* max. freq. count, equal to 8 times the entropy sample length */ + sec_out32(&rng->rtfreqmax, ent_delay << 3); + /* put RNG4 into run mode */ + sec_clrbits32(&rng->rtmctl, RTMCTL_PRGM); +} + +static int rng_init(void) +{ + int ret, ent_delay = RTSDCTL_ENT_DLY_MIN; + ccsr_sec_t __iomem *sec = + (ccsr_sec_t __iomem *)CONFIG_SYS_FSL_SEC_ADDR; + struct rng4tst __iomem *rng = + (struct rng4tst __iomem *)&sec->rng; + + u32 rdsta = sec_in32(&rng->rdsta); + + /* Check if RNG state 0 handler is already instantiated */ + if (rdsta & RNG_STATE0_HANDLE_INSTANTIATED) + return 0; + + do { + /* + * If either of the SH's were instantiated by somebody else + * then it is assumed that the entropy + * parameters are properly set and thus the function + * setting these (kick_trng(...)) is skipped. + * Also, if a handle was instantiated, do not change + * the TRNG parameters. + */ + kick_trng(ent_delay); + ent_delay += 400; + /* + * if instantiate_rng(...) fails, the loop will rerun + * and the kick_trng(...) function will modfiy the + * upper and lower limits of the entropy sampling + * interval, leading to a sucessful initialization of + * the RNG. + */ + ret = instantiate_rng(); + } while ((ret == -1) && (ent_delay < RTSDCTL_ENT_DLY_MAX)); + if (ret) { + printf("RNG: Failed to instantiate RNG\n"); + return ret; + } + + /* Enable RDB bit so that RNG works faster */ + sec_setbits32(&sec->scfgr, SEC_SCFGR_RDBENABLE); + + return ret; +} + int sec_init(void) { int ret = 0; @@ -330,8 +445,18 @@ int sec_init(void) sec_out32(&sec->mcfgr, mcr | 1 << MCFGR_PS_SHIFT); #endif ret = jr_init(); - if (ret < 0) + if (ret < 0) { + printf("SEC initialization failed\n"); return -1; + } + + if (get_rng_vid() >= 4) { + if (rng_init() < 0) { + printf("RNG instantiation failed\n"); + return -1; + } + printf("SEC: RNG instantiated\n"); + } return ret; } |