Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* Copyright (C) 2020 Xiphera Ltd. */
0003 
0004 #include <linux/kernel.h>
0005 #include <linux/module.h>
0006 #include <linux/mod_devicetable.h>
0007 #include <linux/err.h>
0008 #include <linux/io.h>
0009 #include <linux/hw_random.h>
0010 #include <linux/of_device.h>
0011 #include <linux/platform_device.h>
0012 #include <linux/delay.h>
0013 
0014 #define CONTROL_REG         0x00000000
0015 #define STATUS_REG          0x00000004
0016 #define RAND_REG            0x00000000
0017 
0018 #define HOST_TO_TRNG_RESET      0x00000001
0019 #define HOST_TO_TRNG_RELEASE_RESET  0x00000002
0020 #define HOST_TO_TRNG_ENABLE     0x80000000
0021 #define HOST_TO_TRNG_ZEROIZE        0x80000004
0022 #define HOST_TO_TRNG_ACK_ZEROIZE    0x80000008
0023 #define HOST_TO_TRNG_READ       0x8000000F
0024 
0025 /* trng statuses */
0026 #define TRNG_ACK_RESET          0x000000AC
0027 #define TRNG_SUCCESSFUL_STARTUP     0x00000057
0028 #define TRNG_FAILED_STARTUP     0x000000FA
0029 #define TRNG_NEW_RAND_AVAILABLE     0x000000ED
0030 
0031 struct xiphera_trng {
0032     void __iomem *mem;
0033     struct hwrng rng;
0034 };
0035 
0036 static int xiphera_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
0037 {
0038     struct xiphera_trng *trng = container_of(rng, struct xiphera_trng, rng);
0039     int ret = 0;
0040 
0041     while (max >= sizeof(u32)) {
0042         /* check for data */
0043         if (readl(trng->mem + STATUS_REG) == TRNG_NEW_RAND_AVAILABLE) {
0044             *(u32 *)buf = readl(trng->mem + RAND_REG);
0045             /*
0046              * Inform the trng of the read
0047              * and re-enable it to produce a new random number
0048              */
0049             writel(HOST_TO_TRNG_READ, trng->mem + CONTROL_REG);
0050             writel(HOST_TO_TRNG_ENABLE, trng->mem + CONTROL_REG);
0051             ret += sizeof(u32);
0052             buf += sizeof(u32);
0053             max -= sizeof(u32);
0054         } else {
0055             break;
0056         }
0057     }
0058     return ret;
0059 }
0060 
0061 static int xiphera_trng_probe(struct platform_device *pdev)
0062 {
0063     int ret;
0064     struct xiphera_trng *trng;
0065     struct device *dev = &pdev->dev;
0066 
0067     trng = devm_kzalloc(dev, sizeof(*trng), GFP_KERNEL);
0068     if (!trng)
0069         return -ENOMEM;
0070 
0071     trng->mem = devm_platform_ioremap_resource(pdev, 0);
0072     if (IS_ERR(trng->mem))
0073         return PTR_ERR(trng->mem);
0074 
0075     /*
0076      * the trng needs to be reset first which might not happen in time,
0077      * hence we incorporate a small delay to ensure proper behaviour
0078      */
0079     writel(HOST_TO_TRNG_RESET, trng->mem + CONTROL_REG);
0080     usleep_range(100, 200);
0081 
0082     if (readl(trng->mem + STATUS_REG) != TRNG_ACK_RESET) {
0083         /*
0084          * there is a small chance the trng is just not ready yet,
0085          * so we try one more time. If the second time fails, we give up
0086          */
0087         usleep_range(100, 200);
0088         if (readl(trng->mem + STATUS_REG) != TRNG_ACK_RESET) {
0089             dev_err(dev, "failed to reset the trng ip\n");
0090             return -ENODEV;
0091         }
0092     }
0093 
0094     /*
0095      * once again, to ensure proper behaviour we sleep
0096      * for a while after zeroizing the trng
0097      */
0098     writel(HOST_TO_TRNG_RELEASE_RESET, trng->mem + CONTROL_REG);
0099     writel(HOST_TO_TRNG_ENABLE, trng->mem + CONTROL_REG);
0100     writel(HOST_TO_TRNG_ZEROIZE, trng->mem + CONTROL_REG);
0101     msleep(20);
0102 
0103     if (readl(trng->mem + STATUS_REG) != TRNG_SUCCESSFUL_STARTUP) {
0104         /* diagnose the reason for the failure */
0105         if (readl(trng->mem + STATUS_REG) == TRNG_FAILED_STARTUP) {
0106             dev_err(dev, "trng ip startup-tests failed\n");
0107             return -ENODEV;
0108         }
0109         dev_err(dev, "startup-tests yielded no response\n");
0110         return -ENODEV;
0111     }
0112 
0113     writel(HOST_TO_TRNG_ACK_ZEROIZE, trng->mem + CONTROL_REG);
0114 
0115     trng->rng.name = pdev->name;
0116     trng->rng.read = xiphera_trng_read;
0117     trng->rng.quality = 900;
0118 
0119     ret = devm_hwrng_register(dev, &trng->rng);
0120     if (ret) {
0121         dev_err(dev, "failed to register rng device: %d\n", ret);
0122         return ret;
0123     }
0124 
0125     platform_set_drvdata(pdev, trng);
0126 
0127     return 0;
0128 }
0129 
0130 static const struct of_device_id xiphera_trng_of_match[] = {
0131     { .compatible = "xiphera,xip8001b-trng", },
0132     {},
0133 };
0134 MODULE_DEVICE_TABLE(of, xiphera_trng_of_match);
0135 
0136 static struct platform_driver xiphera_trng_driver = {
0137     .driver = {
0138         .name = "xiphera-trng",
0139         .of_match_table = xiphera_trng_of_match,
0140     },
0141     .probe = xiphera_trng_probe,
0142 };
0143 
0144 module_platform_driver(xiphera_trng_driver);
0145 
0146 MODULE_LICENSE("GPL");
0147 MODULE_AUTHOR("Atte Tommiska");
0148 MODULE_DESCRIPTION("Xiphera FPGA-based true random number generator driver");