forked from torvalds/linux
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
crypto: hisilicon/trng - add support for HiSTB TRNG
HiSTB TRNG are found on some HiSilicon STB SoCs. Signed-off-by: David Yang <mmyangfl@gmail.com>
- Loading branch information
1 parent
e6af5c0
commit 3569027
Showing
4 changed files
with
139 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,5 @@ | ||
obj-$(CONFIG_CRYPTO_DEV_HISI_TRNG) += hisi-trng-v2.o | ||
hisi-trng-v2-objs = trng.o | ||
|
||
obj-$(CONFIG_CRYPTO_DEV_HISTB_TRNG) += histb-trng.o | ||
histb-trng-objs += trng-stb.o |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later OR MIT | ||
/* | ||
* Device driver for True RNG in HiSTB SoCs | ||
* | ||
* Copyright (c) 2023 David Yang | ||
*/ | ||
|
||
#include <linux/device.h> | ||
#include <linux/err.h> | ||
#include <linux/hw_random.h> | ||
#include <linux/io.h> | ||
#include <linux/iopoll.h> | ||
#include <linux/module.h> | ||
#include <linux/of_device.h> | ||
|
||
#define HISTB_TRNG_CTRL 0x0 | ||
#define HISTB_TRNG_NUMBER 0x4 | ||
#define HISTB_TRNG_STAT 0x8 | ||
|
||
#define SLEEP_US 10 | ||
#define TIMEOUT_US 10000 | ||
|
||
static int histb_trng_wait(struct hwrng *rng) | ||
{ | ||
void __iomem *base = (void __iomem *) rng->priv; | ||
u32 val; | ||
|
||
return readl_relaxed_poll_timeout(base + HISTB_TRNG_STAT, | ||
val, val & 0x7, SLEEP_US, TIMEOUT_US); | ||
} | ||
|
||
static int histb_trng_init(struct hwrng *rng) | ||
{ | ||
void __iomem *base = (void __iomem *) rng->priv; | ||
u32 val; | ||
|
||
val = readl_relaxed(base + HISTB_TRNG_CTRL); | ||
|
||
/* select rng source 2 */ | ||
val &= ~0x3; | ||
val |= 2; | ||
/* post_process_depth */ | ||
val &= ~(0xf << 8); | ||
val |= 9 << 8; | ||
|
||
val |= BIT(7); /* post_process_enable */ | ||
val |= BIT(5); /* drop_enable */ | ||
|
||
writel_relaxed(val, base + HISTB_TRNG_CTRL); | ||
|
||
/* is device up? */ | ||
if (histb_trng_wait(rng)) { | ||
pr_err("failed to init rng device\n"); | ||
return -EINVAL; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
static int histb_trng_read(struct hwrng *rng, void *data, size_t max, bool wait) | ||
{ | ||
void __iomem *base = (void __iomem *) rng->priv; | ||
size_t i; | ||
int ret; | ||
|
||
for (i = 0; i < max; i += sizeof(u32)) { | ||
ret = histb_trng_wait(rng); | ||
if (ret) { | ||
pr_err("failed to generate random number, generated %d\n", i); | ||
return i ? i : ret; | ||
} | ||
|
||
*((u32 *) data + i) = readl_relaxed(base + HISTB_TRNG_NUMBER); | ||
} | ||
|
||
return i; | ||
} | ||
|
||
static int histb_trng_probe(struct platform_device *pdev) | ||
{ | ||
struct device *dev = &pdev->dev; | ||
struct hwrng *rng; | ||
struct resource *res; | ||
int ret; | ||
|
||
rng = devm_kzalloc(dev, sizeof(*rng), GFP_KERNEL); | ||
if (!rng) | ||
return -ENOMEM; | ||
|
||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
if (!res) | ||
return -ENODEV; | ||
|
||
rng->priv = (unsigned long) devm_ioremap(dev, res->start, resource_size(res)); | ||
if (!rng->priv) | ||
return -ENOMEM; | ||
|
||
rng->name = KBUILD_MODNAME; | ||
rng->init = histb_trng_init; | ||
rng->read = histb_trng_read; | ||
|
||
ret = devm_hwrng_register(dev, rng); | ||
if (ret) { | ||
dev_err(dev, "failed to register %s (%d)\n", rng->name, ret); | ||
return ret; | ||
} | ||
|
||
platform_set_drvdata(pdev, rng); | ||
return 0; | ||
} | ||
|
||
static const struct of_device_id histb_trng_of_match[] = { | ||
{ .compatible = "hisilicon,histb-trng", }, | ||
{ } | ||
}; | ||
|
||
static struct platform_driver histb_trng_driver = { | ||
.probe = histb_trng_probe, | ||
.driver = { | ||
.name = "histb-trng", | ||
.of_match_table = of_match_ptr(histb_trng_of_match), | ||
}, | ||
}; | ||
|
||
module_platform_driver(histb_trng_driver); | ||
|
||
MODULE_DESCRIPTION("HiSTB True RNG"); | ||
MODULE_LICENSE("Dual MIT/GPL"); |