Skip to content

Commit ceec5f5

Browse files
vinodkoulherbertx
authored andcommitted
crypto: qcom-rng - Add Qcom prng driver
This ports the Qcom prng from older hw_random driver. No change of functionality and move from hw_random to crypto APIs is done. Reviewed-by: Linus Walleij <[email protected]> Signed-off-by: Vinod Koul <[email protected]> Signed-off-by: Herbert Xu <[email protected]>
1 parent d978b03 commit ceec5f5

File tree

3 files changed

+220
-0
lines changed

3 files changed

+220
-0
lines changed

drivers/crypto/Kconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,17 @@ config CRYPTO_DEV_QCE
585585
hardware. To compile this driver as a module, choose M here. The
586586
module will be called qcrypto.
587587

588+
config CRYPTO_DEV_QCOM_RNG
589+
tristate "Qualcomm Random Number Generator Driver"
590+
depends on ARCH_QCOM || COMPILE_TEST
591+
select CRYPTO_RNG
592+
help
593+
This driver provides support for the Random Number
594+
Generator hardware found on Qualcomm SoCs.
595+
596+
To compile this driver as a module, choose M here. The
597+
module will be called qcom-rng. If unsure, say N.
598+
588599
config CRYPTO_DEV_VMX
589600
bool "Support for VMX cryptographic acceleration instructions"
590601
depends on PPC64 && VSX

drivers/crypto/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ obj-$(CONFIG_CRYPTO_DEV_PICOXCELL) += picoxcell_crypto.o
3333
obj-$(CONFIG_CRYPTO_DEV_PPC4XX) += amcc/
3434
obj-$(CONFIG_CRYPTO_DEV_QAT) += qat/
3535
obj-$(CONFIG_CRYPTO_DEV_QCE) += qce/
36+
obj-$(CONFIG_CRYPTO_DEV_QCOM_RNG) += qcom-rng.o
3637
obj-$(CONFIG_CRYPTO_DEV_ROCKCHIP) += rockchip/
3738
obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o
3839
obj-$(CONFIG_CRYPTO_DEV_SAHARA) += sahara.o

drivers/crypto/qcom-rng.c

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
// Copyright (c) 2017-18 Linaro Limited
3+
//
4+
// Based on msm-rng.c and downstream driver
5+
6+
#include <crypto/internal/rng.h>
7+
#include <linux/clk.h>
8+
#include <linux/crypto.h>
9+
#include <linux/module.h>
10+
#include <linux/of.h>
11+
#include <linux/platform_device.h>
12+
13+
/* Device specific register offsets */
14+
#define PRNG_DATA_OUT 0x0000
15+
#define PRNG_STATUS 0x0004
16+
#define PRNG_LFSR_CFG 0x0100
17+
#define PRNG_CONFIG 0x0104
18+
19+
/* Device specific register masks and config values */
20+
#define PRNG_LFSR_CFG_MASK 0x0000ffff
21+
#define PRNG_LFSR_CFG_CLOCKS 0x0000dddd
22+
#define PRNG_CONFIG_HW_ENABLE BIT(1)
23+
#define PRNG_STATUS_DATA_AVAIL BIT(0)
24+
25+
#define WORD_SZ 4
26+
27+
struct qcom_rng {
28+
struct mutex lock;
29+
void __iomem *base;
30+
struct clk *clk;
31+
};
32+
33+
struct qcom_rng_ctx {
34+
struct qcom_rng *rng;
35+
};
36+
37+
static struct qcom_rng *qcom_rng_dev;
38+
39+
static int qcom_rng_read(struct qcom_rng *rng, u8 *data, unsigned int max)
40+
{
41+
unsigned int currsize = 0;
42+
u32 val;
43+
44+
/* read random data from hardware */
45+
do {
46+
val = readl_relaxed(rng->base + PRNG_STATUS);
47+
if (!(val & PRNG_STATUS_DATA_AVAIL))
48+
break;
49+
50+
val = readl_relaxed(rng->base + PRNG_DATA_OUT);
51+
if (!val)
52+
break;
53+
54+
if ((max - currsize) >= WORD_SZ) {
55+
memcpy(data, &val, WORD_SZ);
56+
data += WORD_SZ;
57+
currsize += WORD_SZ;
58+
} else {
59+
/* copy only remaining bytes */
60+
memcpy(data, &val, max - currsize);
61+
break;
62+
}
63+
} while (currsize < max);
64+
65+
return currsize;
66+
}
67+
68+
static int qcom_rng_generate(struct crypto_rng *tfm,
69+
const u8 *src, unsigned int slen,
70+
u8 *dstn, unsigned int dlen)
71+
{
72+
struct qcom_rng_ctx *ctx = crypto_rng_ctx(tfm);
73+
struct qcom_rng *rng = ctx->rng;
74+
int ret;
75+
76+
ret = clk_prepare_enable(rng->clk);
77+
if (ret)
78+
return ret;
79+
80+
mutex_lock(&rng->lock);
81+
82+
ret = qcom_rng_read(rng, dstn, dlen);
83+
84+
mutex_unlock(&rng->lock);
85+
clk_disable_unprepare(rng->clk);
86+
87+
return 0;
88+
}
89+
90+
static int qcom_rng_seed(struct crypto_rng *tfm, const u8 *seed,
91+
unsigned int slen)
92+
{
93+
return 0;
94+
}
95+
96+
static int qcom_rng_enable(struct qcom_rng *rng)
97+
{
98+
u32 val;
99+
int ret;
100+
101+
ret = clk_prepare_enable(rng->clk);
102+
if (ret)
103+
return ret;
104+
105+
/* Enable PRNG only if it is not already enabled */
106+
val = readl_relaxed(rng->base + PRNG_CONFIG);
107+
if (val & PRNG_CONFIG_HW_ENABLE)
108+
goto already_enabled;
109+
110+
val = readl_relaxed(rng->base + PRNG_LFSR_CFG);
111+
val &= ~PRNG_LFSR_CFG_MASK;
112+
val |= PRNG_LFSR_CFG_CLOCKS;
113+
writel(val, rng->base + PRNG_LFSR_CFG);
114+
115+
val = readl_relaxed(rng->base + PRNG_CONFIG);
116+
val |= PRNG_CONFIG_HW_ENABLE;
117+
writel(val, rng->base + PRNG_CONFIG);
118+
119+
already_enabled:
120+
clk_disable_unprepare(rng->clk);
121+
122+
return 0;
123+
}
124+
125+
static int qcom_rng_init(struct crypto_tfm *tfm)
126+
{
127+
struct qcom_rng_ctx *ctx = crypto_tfm_ctx(tfm);
128+
129+
ctx->rng = qcom_rng_dev;
130+
131+
return qcom_rng_enable(ctx->rng);
132+
}
133+
134+
static struct rng_alg qcom_rng_alg = {
135+
.generate = qcom_rng_generate,
136+
.seed = qcom_rng_seed,
137+
.seedsize = 0,
138+
.base = {
139+
.cra_name = "stdrng",
140+
.cra_driver_name = "qcom-rng",
141+
.cra_flags = CRYPTO_ALG_TYPE_RNG,
142+
.cra_priority = 300,
143+
.cra_ctxsize = sizeof(struct qcom_rng_ctx),
144+
.cra_module = THIS_MODULE,
145+
.cra_init = qcom_rng_init,
146+
}
147+
};
148+
149+
static int qcom_rng_probe(struct platform_device *pdev)
150+
{
151+
struct resource *res;
152+
struct qcom_rng *rng;
153+
int ret;
154+
155+
rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL);
156+
if (!rng)
157+
return -ENOMEM;
158+
159+
platform_set_drvdata(pdev, rng);
160+
mutex_init(&rng->lock);
161+
162+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
163+
rng->base = devm_ioremap_resource(&pdev->dev, res);
164+
if (IS_ERR(rng->base))
165+
return PTR_ERR(rng->base);
166+
167+
rng->clk = devm_clk_get(&pdev->dev, "core");
168+
if (IS_ERR(rng->clk))
169+
return PTR_ERR(rng->clk);
170+
171+
qcom_rng_dev = rng;
172+
ret = crypto_register_rng(&qcom_rng_alg);
173+
if (ret) {
174+
dev_err(&pdev->dev, "Register crypto rng failed: %d\n", ret);
175+
qcom_rng_dev = NULL;
176+
}
177+
178+
return ret;
179+
}
180+
181+
static int qcom_rng_remove(struct platform_device *pdev)
182+
{
183+
crypto_unregister_rng(&qcom_rng_alg);
184+
185+
qcom_rng_dev = NULL;
186+
187+
return 0;
188+
}
189+
190+
static const struct of_device_id qcom_rng_of_match[] = {
191+
{ .compatible = "qcom,prng" },
192+
{}
193+
};
194+
MODULE_DEVICE_TABLE(of, qcom_rng_of_match);
195+
196+
static struct platform_driver qcom_rng_driver = {
197+
.probe = qcom_rng_probe,
198+
.remove = qcom_rng_remove,
199+
.driver = {
200+
.name = KBUILD_MODNAME,
201+
.of_match_table = of_match_ptr(qcom_rng_of_match),
202+
}
203+
};
204+
module_platform_driver(qcom_rng_driver);
205+
206+
MODULE_ALIAS("platform:" KBUILD_MODNAME);
207+
MODULE_DESCRIPTION("Qualcomm random number generator driver");
208+
MODULE_LICENSE("GPL v2");

0 commit comments

Comments
 (0)