Linux Audio

Check our new training course

Loading...
v6.8
  1// SPDX-License-Identifier: GPL-2.0
  2/* Copyright (C) 2020 Xiphera Ltd. */
  3
  4#include <linux/kernel.h>
  5#include <linux/module.h>
  6#include <linux/mod_devicetable.h>
  7#include <linux/err.h>
  8#include <linux/io.h>
  9#include <linux/hw_random.h>
 
 10#include <linux/platform_device.h>
 11#include <linux/delay.h>
 12
 13#define CONTROL_REG			0x00000000
 14#define STATUS_REG			0x00000004
 15#define RAND_REG			0x00000000
 16
 17#define HOST_TO_TRNG_RESET		0x00000001
 18#define HOST_TO_TRNG_RELEASE_RESET	0x00000002
 19#define HOST_TO_TRNG_ENABLE		0x80000000
 20#define HOST_TO_TRNG_ZEROIZE		0x80000004
 21#define HOST_TO_TRNG_ACK_ZEROIZE	0x80000008
 22#define HOST_TO_TRNG_READ		0x8000000F
 23
 24/* trng statuses */
 25#define TRNG_ACK_RESET			0x000000AC
 26#define TRNG_SUCCESSFUL_STARTUP		0x00000057
 27#define TRNG_FAILED_STARTUP		0x000000FA
 28#define TRNG_NEW_RAND_AVAILABLE		0x000000ED
 29
 30struct xiphera_trng {
 31	void __iomem *mem;
 32	struct hwrng rng;
 33};
 34
 35static int xiphera_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
 36{
 37	struct xiphera_trng *trng = container_of(rng, struct xiphera_trng, rng);
 38	int ret = 0;
 39
 40	while (max >= sizeof(u32)) {
 41		/* check for data */
 42		if (readl(trng->mem + STATUS_REG) == TRNG_NEW_RAND_AVAILABLE) {
 43			*(u32 *)buf = readl(trng->mem + RAND_REG);
 44			/*
 45			 * Inform the trng of the read
 46			 * and re-enable it to produce a new random number
 47			 */
 48			writel(HOST_TO_TRNG_READ, trng->mem + CONTROL_REG);
 49			writel(HOST_TO_TRNG_ENABLE, trng->mem + CONTROL_REG);
 50			ret += sizeof(u32);
 51			buf += sizeof(u32);
 52			max -= sizeof(u32);
 53		} else {
 54			break;
 55		}
 56	}
 57	return ret;
 58}
 59
 60static int xiphera_trng_probe(struct platform_device *pdev)
 61{
 62	int ret;
 63	struct xiphera_trng *trng;
 64	struct device *dev = &pdev->dev;
 65
 66	trng = devm_kzalloc(dev, sizeof(*trng), GFP_KERNEL);
 67	if (!trng)
 68		return -ENOMEM;
 69
 70	trng->mem = devm_platform_ioremap_resource(pdev, 0);
 71	if (IS_ERR(trng->mem))
 72		return PTR_ERR(trng->mem);
 73
 74	/*
 75	 * the trng needs to be reset first which might not happen in time,
 76	 * hence we incorporate a small delay to ensure proper behaviour
 77	 */
 78	writel(HOST_TO_TRNG_RESET, trng->mem + CONTROL_REG);
 79	usleep_range(100, 200);
 80
 81	if (readl(trng->mem + STATUS_REG) != TRNG_ACK_RESET) {
 82		/*
 83		 * there is a small chance the trng is just not ready yet,
 84		 * so we try one more time. If the second time fails, we give up
 85		 */
 86		usleep_range(100, 200);
 87		if (readl(trng->mem + STATUS_REG) != TRNG_ACK_RESET) {
 88			dev_err(dev, "failed to reset the trng ip\n");
 89			return -ENODEV;
 90		}
 91	}
 92
 93	/*
 94	 * once again, to ensure proper behaviour we sleep
 95	 * for a while after zeroizing the trng
 96	 */
 97	writel(HOST_TO_TRNG_RELEASE_RESET, trng->mem + CONTROL_REG);
 98	writel(HOST_TO_TRNG_ENABLE, trng->mem + CONTROL_REG);
 99	writel(HOST_TO_TRNG_ZEROIZE, trng->mem + CONTROL_REG);
100	msleep(20);
101
102	if (readl(trng->mem + STATUS_REG) != TRNG_SUCCESSFUL_STARTUP) {
103		/* diagnose the reason for the failure */
104		if (readl(trng->mem + STATUS_REG) == TRNG_FAILED_STARTUP) {
105			dev_err(dev, "trng ip startup-tests failed\n");
106			return -ENODEV;
107		}
108		dev_err(dev, "startup-tests yielded no response\n");
109		return -ENODEV;
110	}
111
112	writel(HOST_TO_TRNG_ACK_ZEROIZE, trng->mem + CONTROL_REG);
113
114	trng->rng.name = pdev->name;
115	trng->rng.read = xiphera_trng_read;
116	trng->rng.quality = 900;
117
118	ret = devm_hwrng_register(dev, &trng->rng);
119	if (ret) {
120		dev_err(dev, "failed to register rng device: %d\n", ret);
121		return ret;
122	}
 
 
123
124	return 0;
125}
126
127static const struct of_device_id xiphera_trng_of_match[] = {
128	{ .compatible = "xiphera,xip8001b-trng", },
129	{},
130};
131MODULE_DEVICE_TABLE(of, xiphera_trng_of_match);
132
133static struct platform_driver xiphera_trng_driver = {
134	.driver = {
135		.name = "xiphera-trng",
136		.of_match_table	= xiphera_trng_of_match,
137	},
138	.probe = xiphera_trng_probe,
139};
140
141module_platform_driver(xiphera_trng_driver);
142
143MODULE_LICENSE("GPL");
144MODULE_AUTHOR("Atte Tommiska");
145MODULE_DESCRIPTION("Xiphera FPGA-based true random number generator driver");
v6.2
  1// SPDX-License-Identifier: GPL-2.0
  2/* Copyright (C) 2020 Xiphera Ltd. */
  3
  4#include <linux/kernel.h>
  5#include <linux/module.h>
  6#include <linux/mod_devicetable.h>
  7#include <linux/err.h>
  8#include <linux/io.h>
  9#include <linux/hw_random.h>
 10#include <linux/of_device.h>
 11#include <linux/platform_device.h>
 12#include <linux/delay.h>
 13
 14#define CONTROL_REG			0x00000000
 15#define STATUS_REG			0x00000004
 16#define RAND_REG			0x00000000
 17
 18#define HOST_TO_TRNG_RESET		0x00000001
 19#define HOST_TO_TRNG_RELEASE_RESET	0x00000002
 20#define HOST_TO_TRNG_ENABLE		0x80000000
 21#define HOST_TO_TRNG_ZEROIZE		0x80000004
 22#define HOST_TO_TRNG_ACK_ZEROIZE	0x80000008
 23#define HOST_TO_TRNG_READ		0x8000000F
 24
 25/* trng statuses */
 26#define TRNG_ACK_RESET			0x000000AC
 27#define TRNG_SUCCESSFUL_STARTUP		0x00000057
 28#define TRNG_FAILED_STARTUP		0x000000FA
 29#define TRNG_NEW_RAND_AVAILABLE		0x000000ED
 30
 31struct xiphera_trng {
 32	void __iomem *mem;
 33	struct hwrng rng;
 34};
 35
 36static int xiphera_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
 37{
 38	struct xiphera_trng *trng = container_of(rng, struct xiphera_trng, rng);
 39	int ret = 0;
 40
 41	while (max >= sizeof(u32)) {
 42		/* check for data */
 43		if (readl(trng->mem + STATUS_REG) == TRNG_NEW_RAND_AVAILABLE) {
 44			*(u32 *)buf = readl(trng->mem + RAND_REG);
 45			/*
 46			 * Inform the trng of the read
 47			 * and re-enable it to produce a new random number
 48			 */
 49			writel(HOST_TO_TRNG_READ, trng->mem + CONTROL_REG);
 50			writel(HOST_TO_TRNG_ENABLE, trng->mem + CONTROL_REG);
 51			ret += sizeof(u32);
 52			buf += sizeof(u32);
 53			max -= sizeof(u32);
 54		} else {
 55			break;
 56		}
 57	}
 58	return ret;
 59}
 60
 61static int xiphera_trng_probe(struct platform_device *pdev)
 62{
 63	int ret;
 64	struct xiphera_trng *trng;
 65	struct device *dev = &pdev->dev;
 66
 67	trng = devm_kzalloc(dev, sizeof(*trng), GFP_KERNEL);
 68	if (!trng)
 69		return -ENOMEM;
 70
 71	trng->mem = devm_platform_ioremap_resource(pdev, 0);
 72	if (IS_ERR(trng->mem))
 73		return PTR_ERR(trng->mem);
 74
 75	/*
 76	 * the trng needs to be reset first which might not happen in time,
 77	 * hence we incorporate a small delay to ensure proper behaviour
 78	 */
 79	writel(HOST_TO_TRNG_RESET, trng->mem + CONTROL_REG);
 80	usleep_range(100, 200);
 81
 82	if (readl(trng->mem + STATUS_REG) != TRNG_ACK_RESET) {
 83		/*
 84		 * there is a small chance the trng is just not ready yet,
 85		 * so we try one more time. If the second time fails, we give up
 86		 */
 87		usleep_range(100, 200);
 88		if (readl(trng->mem + STATUS_REG) != TRNG_ACK_RESET) {
 89			dev_err(dev, "failed to reset the trng ip\n");
 90			return -ENODEV;
 91		}
 92	}
 93
 94	/*
 95	 * once again, to ensure proper behaviour we sleep
 96	 * for a while after zeroizing the trng
 97	 */
 98	writel(HOST_TO_TRNG_RELEASE_RESET, trng->mem + CONTROL_REG);
 99	writel(HOST_TO_TRNG_ENABLE, trng->mem + CONTROL_REG);
100	writel(HOST_TO_TRNG_ZEROIZE, trng->mem + CONTROL_REG);
101	msleep(20);
102
103	if (readl(trng->mem + STATUS_REG) != TRNG_SUCCESSFUL_STARTUP) {
104		/* diagnose the reason for the failure */
105		if (readl(trng->mem + STATUS_REG) == TRNG_FAILED_STARTUP) {
106			dev_err(dev, "trng ip startup-tests failed\n");
107			return -ENODEV;
108		}
109		dev_err(dev, "startup-tests yielded no response\n");
110		return -ENODEV;
111	}
112
113	writel(HOST_TO_TRNG_ACK_ZEROIZE, trng->mem + CONTROL_REG);
114
115	trng->rng.name = pdev->name;
116	trng->rng.read = xiphera_trng_read;
117	trng->rng.quality = 900;
118
119	ret = devm_hwrng_register(dev, &trng->rng);
120	if (ret) {
121		dev_err(dev, "failed to register rng device: %d\n", ret);
122		return ret;
123	}
124
125	platform_set_drvdata(pdev, trng);
126
127	return 0;
128}
129
130static const struct of_device_id xiphera_trng_of_match[] = {
131	{ .compatible = "xiphera,xip8001b-trng", },
132	{},
133};
134MODULE_DEVICE_TABLE(of, xiphera_trng_of_match);
135
136static struct platform_driver xiphera_trng_driver = {
137	.driver = {
138		.name = "xiphera-trng",
139		.of_match_table	= xiphera_trng_of_match,
140	},
141	.probe = xiphera_trng_probe,
142};
143
144module_platform_driver(xiphera_trng_driver);
145
146MODULE_LICENSE("GPL");
147MODULE_AUTHOR("Atte Tommiska");
148MODULE_DESCRIPTION("Xiphera FPGA-based true random number generator driver");