1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2019 HiSilicon Limited. */
4 #include <linux/acpi.h>
6 #include <linux/hw_random.h>
8 #include <linux/iopoll.h>
9 #include <linux/kernel.h>
10 #include <linux/module.h>
11 #include <linux/platform_device.h>
12 #include <linux/random.h>
14 #define HISI_TRNG_REG 0x00F0
15 #define HISI_TRNG_BYTES 4
16 #define HISI_TRNG_QUALITY 512
18 #define TIMEOUT_US 10000
25 static int hisi_trng_read(struct hwrng
*rng
, void *buf
, size_t max
, bool wait
)
27 struct hisi_trng
*trng
;
32 trng
= container_of(rng
, struct hisi_trng
, rng
);
35 ret
= readl_poll_timeout(trng
->base
+ HISI_TRNG_REG
, val
,
36 val
, SLEEP_US
, TIMEOUT_US
);
40 if (max
- currsize
>= HISI_TRNG_BYTES
) {
41 memcpy(buf
+ currsize
, &val
, HISI_TRNG_BYTES
);
42 currsize
+= HISI_TRNG_BYTES
;
48 /* copy remaining bytes */
49 memcpy(buf
+ currsize
, &val
, max
- currsize
);
51 } while (currsize
< max
);
56 static int hisi_trng_probe(struct platform_device
*pdev
)
58 struct hisi_trng
*trng
;
61 trng
= devm_kzalloc(&pdev
->dev
, sizeof(*trng
), GFP_KERNEL
);
65 trng
->base
= devm_platform_ioremap_resource(pdev
, 0);
66 if (IS_ERR(trng
->base
))
67 return PTR_ERR(trng
->base
);
69 trng
->rng
.name
= pdev
->name
;
70 trng
->rng
.read
= hisi_trng_read
;
71 trng
->rng
.quality
= HISI_TRNG_QUALITY
;
73 ret
= devm_hwrng_register(&pdev
->dev
, &trng
->rng
);
75 dev_err(&pdev
->dev
, "failed to register hwrng!\n");
80 static const struct acpi_device_id hisi_trng_acpi_match
[] = {
84 MODULE_DEVICE_TABLE(acpi
, hisi_trng_acpi_match
);
86 static struct platform_driver hisi_trng_driver
= {
87 .probe
= hisi_trng_probe
,
89 .name
= "hisi-trng-v2",
90 .acpi_match_table
= ACPI_PTR(hisi_trng_acpi_match
),
94 module_platform_driver(hisi_trng_driver
);
96 MODULE_LICENSE("GPL v2");
97 MODULE_AUTHOR("Weili Qian <qianweili@huawei.com>");
98 MODULE_AUTHOR("Zaibo Xu <xuzaibo@huawei.com>");
99 MODULE_DESCRIPTION("HiSilicon true random number generator V2 driver");