From 25990c804789db3126b8c3c51c5a24232bc08d88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fin=20Maa=C3=9F?= Date: Wed, 4 Dec 2024 16:00:50 +0100 Subject: [PATCH] drivers: entropy: add maxq10xx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit add maxq10xx entropy device. Signed-off-by: Fin Maaß --- drivers/entropy/CMakeLists.txt | 1 + drivers/entropy/Kconfig | 1 + drivers/entropy/Kconfig.maxq10xx | 33 ++++ drivers/entropy/entropy_maxq10xx.c | 233 ++++++++++++++++++++++++ dts/bindings/rng/adi,maxq10xx-trng.yaml | 8 + 5 files changed, 276 insertions(+) create mode 100644 drivers/entropy/Kconfig.maxq10xx create mode 100644 drivers/entropy/entropy_maxq10xx.c create mode 100644 dts/bindings/rng/adi,maxq10xx-trng.yaml diff --git a/drivers/entropy/CMakeLists.txt b/drivers/entropy/CMakeLists.txt index d5588378f6f344..238416b57f53ed 100644 --- a/drivers/entropy/CMakeLists.txt +++ b/drivers/entropy/CMakeLists.txt @@ -34,6 +34,7 @@ zephyr_library_sources_ifdef(CONFIG_ENTROPY_GECKO_SE entropy_gecko_se.c) zephyr_library_sources_ifdef(CONFIG_ENTROPY_PSA_CRYPTO_RNG entropy_psa_crypto.c) zephyr_library_sources_ifdef(CONFIG_ENTROPY_NPCX_DRBG entropy_npcx_drbg.c) zephyr_library_sources_ifdef(CONFIG_ENTROPY_MAX32_TRNG entropy_max32.c) +zephyr_library_sources_ifdef(CONFIG_ENTROPY_MAXQ10XX_RNG entropy_maxq10xx.c) zephyr_library_sources_ifdef(CONFIG_ENTROPY_RENESAS_RA entropy_renesas_ra.c) zephyr_library_link_libraries_ifdef(CONFIG_BUILD_WITH_TFM tfm_api) diff --git a/drivers/entropy/Kconfig b/drivers/entropy/Kconfig index debd0f8d7a110d..c2a19878b07f61 100644 --- a/drivers/entropy/Kconfig +++ b/drivers/entropy/Kconfig @@ -37,6 +37,7 @@ source "drivers/entropy/Kconfig.bt_hci" source "drivers/entropy/Kconfig.psa_crypto" source "drivers/entropy/Kconfig.npcx" source "drivers/entropy/Kconfig.max32" +source "drivers/entropy/Kconfig.maxq10xx" source "drivers/entropy/Kconfig.renesas_ra" config ENTROPY_HAS_DRIVER diff --git a/drivers/entropy/Kconfig.maxq10xx b/drivers/entropy/Kconfig.maxq10xx new file mode 100644 index 00000000000000..a75d6983e2de90 --- /dev/null +++ b/drivers/entropy/Kconfig.maxq10xx @@ -0,0 +1,33 @@ +# MAXQ10XX entropy generator driver configuration + +# Copyright (c) 2025 Vogl Electronic GmbH +# SPDX-License-Identifier: Apache-2.0 + +config ENTROPY_MAXQ10XX_RNG + bool "MAXQ10xx entropy number generator driver" + default y + depends on DT_HAS_ADI_MAXQ10XX_TRNG_ENABLED + select ENTROPY_HAS_DRIVER + select SPI + select CRC + help + This option enables the entropy number generator driver for the + MAXQ10xx crypto chips. + +# Don't use use the MAXQ10XX RNG as a random source since it can be quite slow. +# Instead, use the software implemented xoshiro RNG. +choice RNG_GENERATOR_CHOICE + default XOSHIRO_RANDOM_GENERATOR if ENTROPY_MAXQ10XX_RNG +endchoice + +if ENTROPY_MAXQ10XX_RNG + +config ENTROPY_MAXQ10XX_RNG_INIT_PRIORITY + int "MAXQ10xx entropy init priority" + default 51 + help + Device driver initialization priority. + Device is connected to SPI bus, it has to + be initialized after SPI driver. + +endif # ENTROPY_MAXQ10XX_RNG diff --git a/drivers/entropy/entropy_maxq10xx.c b/drivers/entropy/entropy_maxq10xx.c new file mode 100644 index 00000000000000..b6d04cccc0de7e --- /dev/null +++ b/drivers/entropy/entropy_maxq10xx.c @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2024 Vogl Electronic GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT adi_maxq10xx_trng + +#include +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(entropy_maxq10xx, CONFIG_ENTROPY_LOG_LEVEL); + +#define MAXQ10XX_CMD_HEADER 0xAA +#define MAXQ10XX_CMD_GET_RANDOM 0xC9 +#define MAXQ10XX_CMD_GET_RANDOM_INPUT_DATA 0x02 +#define MAXQ10XX_CMD_READ_READY 0x55 + +#define MAXQ10XX_CRC16_POLYNOMIAL 0xA001 +#define MAXQ10XX_CRC16_INITIAL_VALUE 0x0000 + +#define MAXQ10XX_WAIT_TIME K_MSEC(1) + +struct entropy_maxq10xx_config { + struct spi_dt_spec spi; +}; + +struct entropy_maxq10xx_data { + struct k_sem sem_lock; +}; + +static int entropy_maxq10xx_send_cmd(const struct device *dev, uint16_t length) +{ + const struct entropy_maxq10xx_config *config = dev->config; + + uint8_t buffer_tx[9]; + uint16_t crc; + int ret; + + buffer_tx[0] = MAXQ10XX_CMD_HEADER; + buffer_tx[1] = 0x00; + buffer_tx[2] = MAXQ10XX_CMD_GET_RANDOM; + buffer_tx[3] = 0x00; + buffer_tx[4] = MAXQ10XX_CMD_GET_RANDOM_INPUT_DATA; + + sys_put_be16(length, &buffer_tx[5]); + + crc = crc16_reflect(MAXQ10XX_CRC16_POLYNOMIAL, MAXQ10XX_CRC16_INITIAL_VALUE, buffer_tx, 7); + + sys_put_le16(crc, &buffer_tx[7]); + + const struct spi_buf tx_buf[] = {{ + .buf = buffer_tx, + .len = ARRAY_SIZE(buffer_tx), + }}; + const struct spi_buf_set tx = { + .buffers = tx_buf, + .count = ARRAY_SIZE(tx_buf), + }; + + LOG_HEXDUMP_DBG(buffer_tx, sizeof(buffer_tx), "TX buffer"); + + ret = spi_write_dt(&config->spi, &tx); + + return ret; +} + +static int entropy_maxq10xx_wait(const struct device *dev) +{ + const struct entropy_maxq10xx_config *config = dev->config; + uint8_t buffer_rx[1]; + int ret; + + const struct spi_buf rx_buf[] = {{ + .buf = buffer_rx, + .len = ARRAY_SIZE(buffer_rx), + }}; + const struct spi_buf_set rx = { + .buffers = rx_buf, + .count = ARRAY_SIZE(rx_buf), + }; + + while (1) { + ret = spi_read_dt(&config->spi, &rx); + if ((ret < 0) || (buffer_rx[0] == MAXQ10XX_CMD_READ_READY)) { + break; + } + + k_sleep(MAXQ10XX_WAIT_TIME); + }; + + return ret; +} + +static int entropy_maxq10xx_read(const struct device *dev, uint8_t *buffer, uint16_t length) +{ + const struct entropy_maxq10xx_config *config = dev->config; + uint8_t execution_status[2]; + uint8_t length_data[2]; + uint8_t crc[2]; + uint16_t crc_calc; + int ret; + + const struct spi_buf rx_buf[] = { + { + .buf = execution_status, + .len = ARRAY_SIZE(execution_status), + }, + { + .buf = length_data, + .len = ARRAY_SIZE(length_data), + } + }; + const struct spi_buf_set rx = { + .buffers = rx_buf, + .count = ARRAY_SIZE(rx_buf), + }; + + ret = spi_read_dt(&config->spi, &rx); + if (ret < 0) { + return ret; + } + + if (execution_status[0] != 0x00 || execution_status[1] != 0x00) { + LOG_DBG("Execution status: 0x%02X 0x%02X", execution_status[0], + execution_status[1]); + return -EIO; + } + + if (length != sys_get_be16(length_data)) { + LOG_ERR("Length mismatch: %d != %d", length, sys_get_be16(length_data)); + return -EIO; + } + + const struct spi_buf rx_data_buf[] = { + { + .buf = buffer, + .len = length, + }, + { + .buf = crc, + .len = sizeof(crc), + } + }; + + const struct spi_buf_set rx_data = { + .buffers = rx_data_buf, + .count = ARRAY_SIZE(rx_data_buf), + }; + + ret = spi_read_dt(&config->spi, &rx_data); + if (ret < 0) { + return ret; + } + + uint8_t header_tx[1] = {MAXQ10XX_CMD_READ_READY}; + + crc_calc = crc16_reflect(MAXQ10XX_CRC16_POLYNOMIAL, MAXQ10XX_CRC16_INITIAL_VALUE, header_tx, + sizeof(header_tx)); + crc_calc = crc16_reflect(MAXQ10XX_CRC16_POLYNOMIAL, crc_calc, execution_status, + sizeof(execution_status)); + crc_calc = crc16_reflect(MAXQ10XX_CRC16_POLYNOMIAL, crc_calc, length_data, + sizeof(length_data)); + crc_calc = crc16_reflect(MAXQ10XX_CRC16_POLYNOMIAL, crc_calc, buffer, length); + + if (crc_calc != sys_get_le16(crc)) { + LOG_ERR("CRC error: 0x%04X != 0x%04X", crc_calc, sys_get_le16(crc)); + return -EIO; + } + + return ret; +} + +static int entropy_maxq10xx_get_entropy(const struct device *dev, uint8_t *buffer, uint16_t length) +{ + struct entropy_maxq10xx_data *dev_data = dev->data; + + int ret; + + k_sem_take(&dev_data->sem_lock, K_FOREVER); + + ret = entropy_maxq10xx_send_cmd(dev, length); + if (ret < 0) { + LOG_ERR("Failed to send command"); + goto exit; + } + + ret = entropy_maxq10xx_wait(dev); + if (ret < 0) { + LOG_ERR("Failed to wait for ready"); + goto exit; + } + + ret = entropy_maxq10xx_read(dev, buffer, length); + if (ret < 0) { + LOG_ERR("Failed to read data"); + } +exit: + k_sem_give(&dev_data->sem_lock); + return ret; +} + +static int entropy_maxq10xx_init(const struct device *dev) +{ + struct entropy_maxq10xx_data *dev_data = dev->data; + + k_sem_init(&dev_data->sem_lock, 1, 1); + + return 0; +} + +static DEVICE_API(entropy, entropy_maxq10xx_api) = { + .get_entropy = entropy_maxq10xx_get_entropy +}; + +BUILD_ASSERT(CONFIG_SPI_INIT_PRIORITY < CONFIG_ENTROPY_MAXQ10XX_RNG_INIT_PRIORITY, + "SPI driver must be initialized before maxq10 entropy driver"); + +#define DEFINE_MAXQ10XX_ENTROPY(_num) \ + static const struct entropy_maxq10xx_config entropy_maxq10xx_config##_num = { \ + .spi = SPI_DT_SPEC_INST_GET(_num, SPI_WORD_SET(8), 0), \ + }; \ + static struct entropy_maxq10xx_data entropy_maxq10xx_data##_num; \ + DEVICE_DT_INST_DEFINE(_num, entropy_maxq10xx_init, NULL, &entropy_maxq10xx_data##_num, \ + &entropy_maxq10xx_config##_num, POST_KERNEL, \ + CONFIG_ENTROPY_MAXQ10XX_RNG_INIT_PRIORITY, &entropy_maxq10xx_api); + +DT_INST_FOREACH_STATUS_OKAY(DEFINE_MAXQ10XX_ENTROPY); diff --git a/dts/bindings/rng/adi,maxq10xx-trng.yaml b/dts/bindings/rng/adi,maxq10xx-trng.yaml new file mode 100644 index 00000000000000..b9c32305f6c2d1 --- /dev/null +++ b/dts/bindings/rng/adi,maxq10xx-trng.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2024 Vogl Electronic GmbH +# SPDX-License-Identifier: Apache-2.0 + +description: ADI MAXQ10XX RNG + +compatible: "adi,maxq10xx-trng" + +include: spi-device.yaml