From: "Marek Behún" <kabel@kernel.org>
To: "Gregory CLEMENT" <gregory.clement@bootlin.com>,
"Arnd Bergmann" <arnd@arndb.de>,
soc@kernel.org, arm@kernel.org,
"Andy Shevchenko" <andy@kernel.org>,
"Hans de Goede" <hdegoede@redhat.com>,
"Ilpo Järvinen" <ilpo.jarvinen@linux.intel.com>,
"Olivia Mackall" <olivia@selenic.com>,
"Herbert Xu" <herbert@gondor.apana.org.au>,
"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
linux-crypto@vger.kernel.org
Cc: "Marek Behún" <kabel@kernel.org>
Subject: [PATCH v11 6/8] platform: cznic: turris-omnia-mcu: Add support for MCU provided TRNG
Date: Wed, 5 Jun 2024 18:18:49 +0200 [thread overview]
Message-ID: <20240605161851.13911-7-kabel@kernel.org> (raw)
In-Reply-To: <20240605161851.13911-1-kabel@kernel.org>
Add support for true random number generator provided by the MCU.
New Omnia boards come without the Atmel SHA204-A chip. Instead the
crypto functionality is provided by new microcontroller, which has
a TRNG peripheral.
Signed-off-by: Marek Behún <kabel@kernel.org>
---
drivers/platform/cznic/Kconfig | 2 +
drivers/platform/cznic/Makefile | 1 +
.../platform/cznic/turris-omnia-mcu-base.c | 6 +-
.../platform/cznic/turris-omnia-mcu-gpio.c | 2 +-
.../platform/cznic/turris-omnia-mcu-trng.c | 103 ++++++++++++++++++
drivers/platform/cznic/turris-omnia-mcu.h | 8 ++
6 files changed, 120 insertions(+), 2 deletions(-)
create mode 100644 drivers/platform/cznic/turris-omnia-mcu-trng.c
diff --git a/drivers/platform/cznic/Kconfig b/drivers/platform/cznic/Kconfig
index e262930b3faf..6edac80d5fa3 100644
--- a/drivers/platform/cznic/Kconfig
+++ b/drivers/platform/cznic/Kconfig
@@ -18,6 +18,7 @@ config TURRIS_OMNIA_MCU
depends on I2C
select GPIOLIB
select GPIOLIB_IRQCHIP
+ select HW_RANDOM
select RTC_CLASS
select WATCHDOG_CORE
help
@@ -27,6 +28,7 @@ config TURRIS_OMNIA_MCU
- board poweroff into true low power mode (with voltage regulators
disabled) and the ability to configure wake up from this mode (via
rtcwake)
+ - true random number generator (if available on the MCU)
- MCU watchdog
- GPIO pins
- to get front button press events (the front button can be
diff --git a/drivers/platform/cznic/Makefile b/drivers/platform/cznic/Makefile
index 687f7718c0a1..eae4c6b341ff 100644
--- a/drivers/platform/cznic/Makefile
+++ b/drivers/platform/cznic/Makefile
@@ -4,4 +4,5 @@ obj-$(CONFIG_TURRIS_OMNIA_MCU) += turris-omnia-mcu.o
turris-omnia-mcu-y := turris-omnia-mcu-base.o
turris-omnia-mcu-y += turris-omnia-mcu-gpio.o
turris-omnia-mcu-y += turris-omnia-mcu-sys-off-wakeup.o
+turris-omnia-mcu-y += turris-omnia-mcu-trng.o
turris-omnia-mcu-y += turris-omnia-mcu-watchdog.o
diff --git a/drivers/platform/cznic/turris-omnia-mcu-base.c b/drivers/platform/cznic/turris-omnia-mcu-base.c
index f44996588d38..1d4153a96526 100644
--- a/drivers/platform/cznic/turris-omnia-mcu-base.c
+++ b/drivers/platform/cznic/turris-omnia-mcu-base.c
@@ -380,7 +380,11 @@ static int omnia_mcu_probe(struct i2c_client *client)
if (err)
return err;
- return omnia_mcu_register_gpiochip(mcu);
+ err = omnia_mcu_register_gpiochip(mcu);
+ if (err)
+ return err;
+
+ return omnia_mcu_register_trng(mcu);
}
static const struct of_device_id of_omnia_mcu_match[] = {
diff --git a/drivers/platform/cznic/turris-omnia-mcu-gpio.c b/drivers/platform/cznic/turris-omnia-mcu-gpio.c
index bc7965e6c879..972364d3d223 100644
--- a/drivers/platform/cznic/turris-omnia-mcu-gpio.c
+++ b/drivers/platform/cznic/turris-omnia-mcu-gpio.c
@@ -174,7 +174,7 @@ static const struct omnia_gpio omnia_gpios[64] = {
};
/* mapping from interrupts to indexes of GPIOs in the omnia_gpios array */
-static const u8 omnia_int_to_gpio_idx[32] = {
+const u8 omnia_int_to_gpio_idx[32] = {
[__bf_shf(OMNIA_INT_CARD_DET)] = 4,
[__bf_shf(OMNIA_INT_MSATA_IND)] = 5,
[__bf_shf(OMNIA_INT_USB30_OVC)] = 6,
diff --git a/drivers/platform/cznic/turris-omnia-mcu-trng.c b/drivers/platform/cznic/turris-omnia-mcu-trng.c
new file mode 100644
index 000000000000..fbde00f3fca1
--- /dev/null
+++ b/drivers/platform/cznic/turris-omnia-mcu-trng.c
@@ -0,0 +1,103 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * CZ.NIC's Turris Omnia MCU TRNG driver
+ *
+ * 2024 by Marek Behún <kabel@kernel.org>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/completion.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/driver.h>
+#include <linux/hw_random.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/minmax.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/turris-omnia-mcu-interface.h>
+#include <linux/types.h>
+
+#include "turris-omnia-mcu.h"
+
+#define OMNIA_CMD_TRNG_MAX_ENTROPY_LEN 64
+
+static irqreturn_t omnia_trng_irq_handler(int irq, void *dev_id)
+{
+ struct omnia_mcu *mcu = dev_id;
+
+ complete(&mcu->trng_completion);
+
+ return IRQ_HANDLED;
+}
+
+static int omnia_trng_read(struct hwrng *rng, void *data, size_t max, bool wait)
+{
+ struct omnia_mcu *mcu = (struct omnia_mcu *)rng->priv;
+ u8 reply[1 + OMNIA_CMD_TRNG_MAX_ENTROPY_LEN];
+ int err, bytes;
+
+ if (!wait && !completion_done(&mcu->trng_completion))
+ return 0;
+
+ do {
+ if (wait_for_completion_interruptible(&mcu->trng_completion))
+ return -ERESTARTSYS;
+
+ err = omnia_cmd_read(mcu->client,
+ OMNIA_CMD_TRNG_COLLECT_ENTROPY,
+ reply, sizeof(reply));
+ if (err)
+ return err;
+
+ bytes = min3(reply[0], max, OMNIA_CMD_TRNG_MAX_ENTROPY_LEN);
+ } while (wait && !bytes);
+
+ memcpy(data, &reply[1], bytes);
+
+ return bytes;
+}
+
+int omnia_mcu_register_trng(struct omnia_mcu *mcu)
+{
+ struct device *dev = &mcu->client->dev;
+ u8 irq_idx, dummy;
+ int irq, err;
+
+ if (!(mcu->features & OMNIA_FEAT_TRNG))
+ return 0;
+
+ irq_idx = omnia_int_to_gpio_idx[__bf_shf(OMNIA_INT_TRNG)];
+ irq = gpiod_to_irq(gpiochip_get_desc(&mcu->gc, irq_idx));
+ if (irq < 0)
+ return dev_err_probe(dev, irq, "Cannot get TRNG IRQ\n");
+
+ /*
+ * If someone else cleared the TRNG interrupt but did not read the
+ * entropy, a new interrupt won't be generated, and entropy collection
+ * will be stuck. Ensure an interrupt will be generated by executing
+ * the collect entropy command (and discarding the result).
+ */
+ err = omnia_cmd_read(mcu->client, OMNIA_CMD_TRNG_COLLECT_ENTROPY,
+ &dummy, 1);
+ if (err)
+ return err;
+
+ init_completion(&mcu->trng_completion);
+
+ err = devm_request_threaded_irq(dev, irq, NULL, omnia_trng_irq_handler,
+ IRQF_ONESHOT, "turris-omnia-mcu-trng",
+ mcu);
+ if (err)
+ return dev_err_probe(dev, err, "Cannot request TRNG IRQ\n");
+
+ mcu->trng.name = "turris-omnia-mcu-trng";
+ mcu->trng.read = omnia_trng_read;
+ mcu->trng.priv = (unsigned long)mcu;
+
+ err = devm_hwrng_register(dev, &mcu->trng);
+ if (err)
+ return dev_err_probe(dev, err, "Cannot register TRNG\n");
+
+ return 0;
+}
diff --git a/drivers/platform/cznic/turris-omnia-mcu.h b/drivers/platform/cznic/turris-omnia-mcu.h
index 5f846909934f..ee8d58516156 100644
--- a/drivers/platform/cznic/turris-omnia-mcu.h
+++ b/drivers/platform/cznic/turris-omnia-mcu.h
@@ -9,7 +9,9 @@
#define __TURRIS_OMNIA_MCU_H
#include <linux/bitops.h>
+#include <linux/completion.h>
#include <linux/gpio/driver.h>
+#include <linux/hw_random.h>
#include <linux/if_ether.h>
#include <linux/mutex.h>
#include <linux/rtc.h>
@@ -47,6 +49,10 @@ struct omnia_mcu {
/* MCU watchdog */
struct watchdog_device wdt;
+
+ /* true random number generator */
+ struct hwrng trng;
+ struct completion trng_completion;
};
int omnia_cmd_write_read(const struct i2c_client *client,
@@ -176,11 +182,13 @@ static inline int omnia_cmd_read_u8(const struct i2c_client *client, u8 cmd,
return omnia_cmd_read(client, cmd, reply, sizeof(*reply));
}
+extern const u8 omnia_int_to_gpio_idx[32];
extern const struct attribute_group omnia_mcu_gpio_group;
extern const struct attribute_group omnia_mcu_poweroff_group;
int omnia_mcu_register_gpiochip(struct omnia_mcu *mcu);
int omnia_mcu_register_sys_off_and_wakeup(struct omnia_mcu *mcu);
+int omnia_mcu_register_trng(struct omnia_mcu *mcu);
int omnia_mcu_register_watchdog(struct omnia_mcu *mcu);
#endif /* __TURRIS_OMNIA_MCU_H */
--
2.44.2
next prev parent reply other threads:[~2024-06-05 16:19 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-06-05 16:18 [PATCH v11 0/8] Turris Omnia MCU driver Marek Behún
2024-06-05 16:18 ` [PATCH v11 1/8] dt-bindings: firmware: add cznic,turris-omnia-mcu binding Marek Behún
2024-06-05 16:18 ` [PATCH v11 2/8] platform: cznic: Add preliminary support for Turris Omnia MCU Marek Behún
2024-06-05 18:04 ` Andy Shevchenko
2024-06-05 16:18 ` [PATCH v11 3/8] platform: cznic: turris-omnia-mcu: Add support for MCU connected GPIOs Marek Behún
2024-06-05 18:29 ` Andy Shevchenko
2024-06-05 19:03 ` Andy Shevchenko
2024-06-05 16:18 ` [PATCH v11 4/8] platform: cznic: turris-omnia-mcu: Add support for poweroff and wakeup Marek Behún
2024-06-05 18:41 ` Andy Shevchenko
2024-06-06 8:01 ` Marek Behún
2024-06-05 16:18 ` [PATCH v11 5/8] platform: cznic: turris-omnia-mcu: Add support for MCU watchdog Marek Behún
2024-06-05 18:45 ` Andy Shevchenko
2024-06-05 16:18 ` Marek Behún [this message]
2024-06-05 19:00 ` [PATCH v11 6/8] platform: cznic: turris-omnia-mcu: Add support for MCU provided TRNG Andy Shevchenko
2024-06-06 8:53 ` Marek Behún
2024-06-06 10:11 ` Andy Shevchenko
2024-06-06 12:37 ` Marek Behún
2024-06-06 9:11 ` Marek Behún
2024-06-06 9:35 ` Andy Shevchenko
2024-06-17 8:38 ` Bartosz Golaszewski
2024-06-17 8:56 ` Marek Behún
2024-06-17 9:07 ` Bartosz Golaszewski
2024-06-17 10:42 ` Andy Shevchenko
2024-06-17 11:34 ` Marek Behún
2024-06-17 13:35 ` Bartosz Golaszewski
2024-06-07 10:30 ` Herbert Xu
2024-06-07 16:15 ` Marek Behún
2024-06-05 16:18 ` [PATCH v11 7/8] ARM: dts: turris-omnia: Add MCU system-controller node Marek Behún
2024-06-05 16:18 ` [PATCH v11 8/8] ARM: dts: turris-omnia: Add GPIO key node for front button Marek Behún
2024-06-05 19:05 ` [PATCH v11 0/8] Turris Omnia MCU driver Andy Shevchenko
2024-06-06 7:25 ` Marek Behún
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240605161851.13911-7-kabel@kernel.org \
--to=kabel@kernel.org \
--cc=andy@kernel.org \
--cc=arm@kernel.org \
--cc=arnd@arndb.de \
--cc=gregkh@linuxfoundation.org \
--cc=gregory.clement@bootlin.com \
--cc=hdegoede@redhat.com \
--cc=herbert@gondor.apana.org.au \
--cc=ilpo.jarvinen@linux.intel.com \
--cc=linux-crypto@vger.kernel.org \
--cc=olivia@selenic.com \
--cc=soc@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.