Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * ST Random Number Generator Driver ST's Platforms
0004  *
0005  * Author: Pankaj Dev: <pankaj.dev@st.com>
0006  *         Lee Jones <lee.jones@linaro.org>
0007  *
0008  * Copyright (C) 2015 STMicroelectronics (R&D) Limited
0009  */
0010 
0011 #include <linux/clk.h>
0012 #include <linux/delay.h>
0013 #include <linux/hw_random.h>
0014 #include <linux/io.h>
0015 #include <linux/kernel.h>
0016 #include <linux/module.h>
0017 #include <linux/of.h>
0018 #include <linux/platform_device.h>
0019 #include <linux/slab.h>
0020 
0021 /* Registers */
0022 #define ST_RNG_STATUS_REG       0x20
0023 #define ST_RNG_DATA_REG         0x24
0024 
0025 /* Registers fields */
0026 #define ST_RNG_STATUS_BAD_SEQUENCE  BIT(0)
0027 #define ST_RNG_STATUS_BAD_ALTERNANCE    BIT(1)
0028 #define ST_RNG_STATUS_FIFO_FULL     BIT(5)
0029 
0030 #define ST_RNG_SAMPLE_SIZE      2 /* 2 Byte (16bit) samples */
0031 #define ST_RNG_FIFO_DEPTH       4
0032 #define ST_RNG_FIFO_SIZE        (ST_RNG_FIFO_DEPTH * ST_RNG_SAMPLE_SIZE)
0033 
0034 /*
0035  * Samples are documented to be available every 0.667us, so in theory
0036  * the 4 sample deep FIFO should take 2.668us to fill.  However, during
0037  * thorough testing, it became apparent that filling the FIFO actually
0038  * takes closer to 12us.  We then multiply by 2 in order to account for
0039  * the lack of udelay()'s reliability, suggested by Russell King.
0040  */
0041 #define ST_RNG_FILL_FIFO_TIMEOUT    (12 * 2)
0042 
0043 struct st_rng_data {
0044     void __iomem    *base;
0045     struct clk  *clk;
0046     struct hwrng    ops;
0047 };
0048 
0049 static int st_rng_read(struct hwrng *rng, void *data, size_t max, bool wait)
0050 {
0051     struct st_rng_data *ddata = (struct st_rng_data *)rng->priv;
0052     u32 status;
0053     int i;
0054 
0055     /* Wait until FIFO is full - max 4uS*/
0056     for (i = 0; i < ST_RNG_FILL_FIFO_TIMEOUT; i++) {
0057         status = readl_relaxed(ddata->base + ST_RNG_STATUS_REG);
0058         if (status & ST_RNG_STATUS_FIFO_FULL)
0059             break;
0060         udelay(1);
0061     }
0062 
0063     if (i == ST_RNG_FILL_FIFO_TIMEOUT)
0064         return 0;
0065 
0066     for (i = 0; i < ST_RNG_FIFO_SIZE && i < max; i += 2)
0067         *(u16 *)(data + i) =
0068             readl_relaxed(ddata->base + ST_RNG_DATA_REG);
0069 
0070     return i;   /* No of bytes read */
0071 }
0072 
0073 static int st_rng_probe(struct platform_device *pdev)
0074 {
0075     struct st_rng_data *ddata;
0076     struct clk *clk;
0077     void __iomem *base;
0078     int ret;
0079 
0080     ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
0081     if (!ddata)
0082         return -ENOMEM;
0083 
0084     base = devm_platform_ioremap_resource(pdev, 0);
0085     if (IS_ERR(base))
0086         return PTR_ERR(base);
0087 
0088     clk = devm_clk_get(&pdev->dev, NULL);
0089     if (IS_ERR(clk))
0090         return PTR_ERR(clk);
0091 
0092     ret = clk_prepare_enable(clk);
0093     if (ret)
0094         return ret;
0095 
0096     ddata->ops.priv = (unsigned long)ddata;
0097     ddata->ops.read = st_rng_read;
0098     ddata->ops.name = pdev->name;
0099     ddata->base = base;
0100     ddata->clk  = clk;
0101 
0102     dev_set_drvdata(&pdev->dev, ddata);
0103 
0104     ret = devm_hwrng_register(&pdev->dev, &ddata->ops);
0105     if (ret) {
0106         dev_err(&pdev->dev, "Failed to register HW RNG\n");
0107         clk_disable_unprepare(clk);
0108         return ret;
0109     }
0110 
0111     dev_info(&pdev->dev, "Successfully registered HW RNG\n");
0112 
0113     return 0;
0114 }
0115 
0116 static int st_rng_remove(struct platform_device *pdev)
0117 {
0118     struct st_rng_data *ddata = dev_get_drvdata(&pdev->dev);
0119 
0120     clk_disable_unprepare(ddata->clk);
0121 
0122     return 0;
0123 }
0124 
0125 static const struct of_device_id st_rng_match[] __maybe_unused = {
0126     { .compatible = "st,rng" },
0127     {},
0128 };
0129 MODULE_DEVICE_TABLE(of, st_rng_match);
0130 
0131 static struct platform_driver st_rng_driver = {
0132     .driver = {
0133         .name = "st-hwrandom",
0134         .of_match_table = of_match_ptr(st_rng_match),
0135     },
0136     .probe = st_rng_probe,
0137     .remove = st_rng_remove
0138 };
0139 
0140 module_platform_driver(st_rng_driver);
0141 
0142 MODULE_AUTHOR("Pankaj Dev <pankaj.dev@st.com>");
0143 MODULE_LICENSE("GPL v2");