Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <linus.walleij@linaro.org>
Signed-off-by: Vinod Koul <vkoul@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

authored by

Vinod Koul and committed by
Herbert Xu
ceec5f5b d978b031

+220
+11
drivers/crypto/Kconfig
··· 585 585 hardware. To compile this driver as a module, choose M here. The 586 586 module will be called qcrypto. 587 587 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 + 588 599 config CRYPTO_DEV_VMX 589 600 bool "Support for VMX cryptographic acceleration instructions" 590 601 depends on PPC64 && VSX
+1
drivers/crypto/Makefile
··· 33 33 obj-$(CONFIG_CRYPTO_DEV_PPC4XX) += amcc/ 34 34 obj-$(CONFIG_CRYPTO_DEV_QAT) += qat/ 35 35 obj-$(CONFIG_CRYPTO_DEV_QCE) += qce/ 36 + obj-$(CONFIG_CRYPTO_DEV_QCOM_RNG) += qcom-rng.o 36 37 obj-$(CONFIG_CRYPTO_DEV_ROCKCHIP) += rockchip/ 37 38 obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o 38 39 obj-$(CONFIG_CRYPTO_DEV_SAHARA) += sahara.o
+208
drivers/crypto/qcom-rng.c
··· 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");