/* * TRNG collects osc ring output bit every RK_RNG_SAMPLE_CNT time. The value is * a tradeoff between speed and quality and has been adjusted to get a quality * of ~900 (~87.5% of FIPS 140-2 successes).
*/ #define RK_RNG_SAMPLE_CNT 1000
/* after how many bytes of output TRNGv1 implementations should be reseeded */ #define RK_TRNG_V1_AUTO_RESEED_CNT 16000
/* * TRNG V1 register definitions * The TRNG V1 IP is a stand-alone TRNG implementation (not part of a crypto IP) * and can be found in the Rockchip RK3588 SoC
*/ #define TRNG_V1_CTRL 0x0000 #define TRNG_V1_CTRL_NOP 0x00 #define TRNG_V1_CTRL_RAND 0x01 #define TRNG_V1_CTRL_SEED 0x02
/* Auto Reseed Register */ #define TRNG_V1_AUTO_RQSTS 0x0060
#define TRNG_V1_VERSION 0x00F0 #define TRNG_v1_VERSION_CODE 0x46bc /* end of TRNG_V1 register definitions */
/* * RKRNG register definitions * The RKRNG IP is a stand-alone TRNG implementation (not part of a crypto IP) * and can be found in the Rockchip RK3576, Rockchip RK3562 and Rockchip RK3528 * SoCs. It can either output true randomness (TRNG) or "deterministic" * randomness derived from hashing the true entropy (DRNG). This driver * implementation uses just the true entropy, and leaves stretching the entropy * up to Linux.
*/ #define RKRNG_CFG 0x0000 #define RKRNG_CTRL 0x0010 #define RKRNG_CTRL_REQ_TRNG BIT(4) #define RKRNG_STATE 0x0014 #define RKRNG_STATE_TRNG_RDY BIT(4) #define RKRNG_TRNG_DATA0 0x0050 #define RKRNG_TRNG_DATA1 0x0054 #define RKRNG_TRNG_DATA2 0x0058 #define RKRNG_TRNG_DATA3 0x005C #define RKRNG_TRNG_DATA4 0x0060 #define RKRNG_TRNG_DATA5 0x0064 #define RKRNG_TRNG_DATA6 0x0068 #define RKRNG_TRNG_DATA7 0x006C #define RKRNG_READ_LEN 32
/* Before removing this assert, give rk3588_rng_read an upper bound of 32 */
static_assert(RK_RNG_MAX_BYTE <= (TRNG_V1_RAND7 + 4 - TRNG_V1_RAND0), "You raised RK_RNG_MAX_BYTE and broke rk3588-rng, congrats.");
ret = rk_rng_enable_clks(rk_rng); if (ret < 0) return ret;
/* set the sample period */
writel(RK_RNG_SAMPLE_CNT, rk_rng->base + TRNG_RNG_SAMPLE_CNT);
/* set osc ring speed and enable it */
rk_rng_write_ctl(rk_rng, TRNG_RNG_CTL_LEN_256_BIT |
TRNG_RNG_CTL_OSC_RING_SPEED_0 |
TRNG_RNG_CTL_ENABLE,
TRNG_RNG_CTL_MASK);
ret = pm_runtime_resume_and_get(rk_rng->dev); if (ret < 0) return ret;
/* Start collecting random data */
rk_rng_write_ctl(rk_rng, TRNG_RNG_CTL_START, TRNG_RNG_CTL_START);
ret = readl_poll_timeout(rk_rng->base + TRNG_RNG_CTL, reg,
!(reg & TRNG_RNG_CTL_START),
RK_RNG_POLL_PERIOD_US,
RK_RNG_POLL_TIMEOUT_US); if (ret < 0) goto out;
/* Read random data stored in the registers */
memcpy_fromio(buf, rk_rng->base + TRNG_RNG_DOUT, to_read);
out:
pm_runtime_put_sync_autosuspend(rk_rng->dev);
ret = rk_rng_enable_clks(rk_rng); if (ret < 0) return ret;
version = rk_rng_readl(rk_rng, TRNG_V1_VERSION); if (version != TRNG_v1_VERSION_CODE) {
dev_err(rk_rng->dev, "wrong trng version, expected = %08x, actual = %08x\n",
TRNG_V1_VERSION, version);
ret = -EFAULT; goto err_disable_clk;
}
mask = TRNG_V1_STAT_SEEDED | TRNG_V1_STAT_GENERATING |
TRNG_V1_STAT_RESEEDING; if (readl_poll_timeout(rk_rng->base + TRNG_V1_STAT, status,
(status & mask) == TRNG_V1_STAT_SEEDED,
RK_RNG_POLL_PERIOD_US, RK_RNG_POLL_TIMEOUT_US) < 0) {
dev_err(rk_rng->dev, "timed out waiting for hwrng to reseed\n");
ret = -ETIMEDOUT; goto err_disable_clk;
}
/* * clear ISTAT flag, downstream advises to do this to avoid * auto-reseeding "on power on"
*/
istat = rk_rng_readl(rk_rng, TRNG_V1_ISTAT);
rk_rng_writel(rk_rng, istat, TRNG_V1_ISTAT);
/* auto reseed after RK_TRNG_V1_AUTO_RESEED_CNT bytes */
rk_rng_writel(rk_rng, RK_TRNG_V1_AUTO_RESEED_CNT / 16, TRNG_V1_AUTO_RQSTS);
ret = pm_runtime_resume_and_get(rk_rng->dev); if (ret < 0) return ret;
/* Clear ISTAT, even without interrupts enabled, this will be updated */
reg = rk_rng_readl(rk_rng, TRNG_V1_ISTAT);
rk_rng_writel(rk_rng, reg, TRNG_V1_ISTAT);
/* generate 256 bits of random data */
rk_rng_writel(rk_rng, TRNG_V1_MODE_256_BIT, TRNG_V1_MODE);
rk_rng_writel(rk_rng, TRNG_V1_CTRL_RAND, TRNG_V1_CTRL);
ret = readl_poll_timeout_atomic(rk_rng->base + TRNG_V1_ISTAT, reg,
(reg & TRNG_V1_ISTAT_RAND_RDY), 0,
RK_RNG_POLL_TIMEOUT_US); if (ret < 0) goto out;
/* Read random data that's in registers TRNG_V1_RAND0 through RAND7 */
memcpy_fromio(buf, rk_rng->base + TRNG_V1_RAND0, to_read);
out: /* Clear ISTAT */
rk_rng_writel(rk_rng, reg, TRNG_V1_ISTAT); /* close the TRNG */
rk_rng_writel(rk_rng, TRNG_V1_CTRL_NOP, TRNG_V1_CTRL);
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.