|
@@ -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;
|
|
|
}
|