/* * Copyright (c) 2018 Aurelien Jarno * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include struct trng_sam_dev_cfg { Trng *regs; }; #define DEV_CFG(dev) \ ((const struct trng_sam_dev_cfg *const)(dev)->config->config_info) static int entropy_sam_wait_ready(Trng *const trng) { /* According to the reference manual, the generator provides * one 32-bit random value every 84 peripheral clock cycles. * MCK may not be smaller than HCLK/4, so it should not take * more than 336 HCLK ticks. Assuming the CPU can do 1 * instruction per HCLK the number of times to loop before * the TRNG is ready is less than 1000. And that is when * assuming the loop only takes 1 instruction. So looping a * million times should be more than enough. */ int timeout = 1000000; while (!(trng->TRNG_ISR & TRNG_ISR_DATRDY)) { if (timeout-- == 0) { return -ETIMEDOUT; } k_yield(); } return 0; } static int entropy_sam_get_entropy(struct device *dev, u8_t *buffer, u16_t length) { Trng *const trng = DEV_CFG(dev)->regs; while (length > 0) { size_t to_copy; u32_t value; int res; res = entropy_sam_wait_ready(trng); if (res < 0) { return res; } value = trng->TRNG_ODATA; to_copy = min(length, sizeof(value)); memcpy(buffer, &value, to_copy); buffer += to_copy; length -= to_copy; } return 0; } static int entropy_sam_init(struct device *dev) { Trng *const trng = DEV_CFG(dev)->regs; /* Enable the user interface clock */ soc_pmc_peripheral_enable(DT_ENTROPY_SAM_TRNG_PERIPHERAL_ID); /* Enable the TRNG */ trng->TRNG_CR = TRNG_CR_KEY_PASSWD | TRNG_CR_ENABLE; return 0; } static const struct entropy_driver_api entropy_sam_api = { .get_entropy = entropy_sam_get_entropy }; static const struct trng_sam_dev_cfg trng_sam_cfg = { .regs = (Trng *)DT_ENTROPY_SAM_TRNG_BASE_ADDRESS, }; DEVICE_AND_API_INIT(entropy_sam, CONFIG_ENTROPY_NAME, entropy_sam_init, NULL, &trng_sam_cfg, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &entropy_sam_api);