struct imx_rngc { struct device *dev; struct clk *clk; void __iomem *base; struct hwrng rng; struct completion rng_op_done; /* * err_reg is written only by the irq handler and read only * when interrupts are masked, we need no spinlock
*/
u32 err_reg;
};
/* * CLR_INT clears the interrupt only if there's no error * CLR_ERR clear the interrupt and the error register if there * is an error
*/
cmd = readl(rngc->base + RNGC_COMMAND);
cmd |= RNGC_CMD_CLR_INT | RNGC_CMD_CLR_ERR;
writel(cmd, rngc->base + RNGC_COMMAND);
}
staticint imx_rngc_self_test(struct imx_rngc *rngc)
{
u32 cmd; int ret;
imx_rngc_irq_unmask(rngc);
/* run self test */
cmd = readl(rngc->base + RNGC_COMMAND);
writel(cmd | RNGC_CMD_SELF_TEST, rngc->base + RNGC_COMMAND);
ret = wait_for_completion_timeout(&rngc->rng_op_done,
usecs_to_jiffies(RNGC_SELFTEST_TIMEOUT));
imx_rngc_irq_mask_clear(rngc); if (!ret) return -ETIMEDOUT;
/* * clearing the interrupt will also clear the error register * read error and status before clearing
*/
status = readl(rngc->base + RNGC_STATUS);
rngc->err_reg = readl(rngc->base + RNGC_ERROR);
imx_rngc_irq_mask_clear(rngc);
if (status & (RNGC_STATUS_SEED_DONE | RNGC_STATUS_ST_DONE))
complete(&rngc->rng_op_done);
/* create seed, repeat while there is some statistical error */ do { /* seed creation */
cmd = readl(rngc->base + RNGC_COMMAND);
writel(cmd | RNGC_CMD_SEED, rngc->base + RNGC_COMMAND);
ret = wait_for_completion_timeout(&rngc->rng_op_done,
msecs_to_jiffies(RNGC_SEED_TIMEOUT)); if (!ret) {
err = -ETIMEDOUT; goto out;
}
} while (rngc->err_reg == RNGC_ERROR_STATUS_STAT_ERR);
if (rngc->err_reg) {
err = -EIO; goto out;
}
/* * enable automatic seeding, the rngc creates a new seed automatically * after serving 2^20 random 160-bit words
*/
ctrl = readl(rngc->base + RNGC_CONTROL);
ctrl |= RNGC_CTRL_AUTO_SEED;
writel(ctrl, rngc->base + RNGC_CONTROL);
out: /* * if initialisation was successful, we keep the interrupt * unmasked until imx_rngc_cleanup is called * we mask the interrupt ourselves if we return an error
*/ if (err)
imx_rngc_irq_mask_clear(rngc);
ret = devm_request_irq(&pdev->dev,
irq, imx_rngc_irq, 0, pdev->name, (void *)rngc); if (ret) {
clk_disable_unprepare(rngc->clk); return dev_err_probe(&pdev->dev, ret, "Can't get interrupt working.\n");
}
if (self_test) {
ret = imx_rngc_self_test(rngc); if (ret) {
clk_disable_unprepare(rngc->clk); return dev_err_probe(&pdev->dev, ret, "self test failed\n");
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.