/* * 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.
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.