Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Nomadik RNG support
0004  *  Copyright 2009 Alessandro Rubini
0005  */
0006 
0007 #include <linux/kernel.h>
0008 #include <linux/module.h>
0009 #include <linux/device.h>
0010 #include <linux/amba/bus.h>
0011 #include <linux/hw_random.h>
0012 #include <linux/io.h>
0013 #include <linux/clk.h>
0014 #include <linux/err.h>
0015 
0016 static struct clk *rng_clk;
0017 
0018 static int nmk_rng_read(struct hwrng *rng, void *data, size_t max, bool wait)
0019 {
0020     void __iomem *base = (void __iomem *)rng->priv;
0021 
0022     /*
0023      * The register is 32 bits and gives 16 random bits (low half).
0024      * A subsequent read will delay the core for 400ns, so we just read
0025      * once and accept the very unlikely very small delay, even if wait==0.
0026      */
0027     *(u16 *)data = __raw_readl(base + 8) & 0xffff;
0028     return 2;
0029 }
0030 
0031 /* we have at most one RNG per machine, granted */
0032 static struct hwrng nmk_rng = {
0033     .name       = "nomadik",
0034     .read       = nmk_rng_read,
0035 };
0036 
0037 static int nmk_rng_probe(struct amba_device *dev, const struct amba_id *id)
0038 {
0039     void __iomem *base;
0040     int ret;
0041 
0042     rng_clk = devm_clk_get(&dev->dev, NULL);
0043     if (IS_ERR(rng_clk)) {
0044         dev_err(&dev->dev, "could not get rng clock\n");
0045         ret = PTR_ERR(rng_clk);
0046         return ret;
0047     }
0048 
0049     clk_prepare_enable(rng_clk);
0050 
0051     ret = amba_request_regions(dev, dev->dev.init_name);
0052     if (ret)
0053         goto out_clk;
0054     ret = -ENOMEM;
0055     base = devm_ioremap(&dev->dev, dev->res.start,
0056                 resource_size(&dev->res));
0057     if (!base)
0058         goto out_release;
0059     nmk_rng.priv = (unsigned long)base;
0060     ret = devm_hwrng_register(&dev->dev, &nmk_rng);
0061     if (ret)
0062         goto out_release;
0063     return 0;
0064 
0065 out_release:
0066     amba_release_regions(dev);
0067 out_clk:
0068     clk_disable_unprepare(rng_clk);
0069     return ret;
0070 }
0071 
0072 static void nmk_rng_remove(struct amba_device *dev)
0073 {
0074     amba_release_regions(dev);
0075     clk_disable_unprepare(rng_clk);
0076 }
0077 
0078 static const struct amba_id nmk_rng_ids[] = {
0079     {
0080         .id = 0x000805e1,
0081         .mask   = 0x000fffff, /* top bits are rev and cfg: accept all */
0082     },
0083     {0, 0},
0084 };
0085 
0086 MODULE_DEVICE_TABLE(amba, nmk_rng_ids);
0087 
0088 static struct amba_driver nmk_rng_driver = {
0089     .drv = {
0090         .owner = THIS_MODULE,
0091         .name = "rng",
0092         },
0093     .probe = nmk_rng_probe,
0094     .remove = nmk_rng_remove,
0095     .id_table = nmk_rng_ids,
0096 };
0097 
0098 module_amba_driver(nmk_rng_driver);
0099 
0100 MODULE_LICENSE("GPL");