Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (c) 2010-2012 Broadcom. All rights reserved.
0004  * Copyright (c) 2013 Lubomir Rintel
0005  */
0006 
0007 #include <linux/hw_random.h>
0008 #include <linux/io.h>
0009 #include <linux/kernel.h>
0010 #include <linux/module.h>
0011 #include <linux/of_address.h>
0012 #include <linux/of_platform.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/printk.h>
0015 #include <linux/clk.h>
0016 #include <linux/reset.h>
0017 
0018 #define RNG_CTRL    0x0
0019 #define RNG_STATUS  0x4
0020 #define RNG_DATA    0x8
0021 #define RNG_INT_MASK    0x10
0022 
0023 /* enable rng */
0024 #define RNG_RBGEN   0x1
0025 
0026 /* the initial numbers generated are "less random" so will be discarded */
0027 #define RNG_WARMUP_COUNT 0x40000
0028 
0029 #define RNG_INT_OFF 0x1
0030 
0031 struct bcm2835_rng_priv {
0032     struct hwrng rng;
0033     void __iomem *base;
0034     bool mask_interrupts;
0035     struct clk *clk;
0036     struct reset_control *reset;
0037 };
0038 
0039 static inline struct bcm2835_rng_priv *to_rng_priv(struct hwrng *rng)
0040 {
0041     return container_of(rng, struct bcm2835_rng_priv, rng);
0042 }
0043 
0044 static inline u32 rng_readl(struct bcm2835_rng_priv *priv, u32 offset)
0045 {
0046     /* MIPS chips strapped for BE will automagically configure the
0047      * peripheral registers for CPU-native byte order.
0048      */
0049     if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
0050         return __raw_readl(priv->base + offset);
0051     else
0052         return readl(priv->base + offset);
0053 }
0054 
0055 static inline void rng_writel(struct bcm2835_rng_priv *priv, u32 val,
0056                   u32 offset)
0057 {
0058     if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
0059         __raw_writel(val, priv->base + offset);
0060     else
0061         writel(val, priv->base + offset);
0062 }
0063 
0064 static int bcm2835_rng_read(struct hwrng *rng, void *buf, size_t max,
0065                    bool wait)
0066 {
0067     struct bcm2835_rng_priv *priv = to_rng_priv(rng);
0068     u32 max_words = max / sizeof(u32);
0069     u32 num_words, count;
0070 
0071     while ((rng_readl(priv, RNG_STATUS) >> 24) == 0) {
0072         if (!wait)
0073             return 0;
0074         cpu_relax();
0075     }
0076 
0077     num_words = rng_readl(priv, RNG_STATUS) >> 24;
0078     if (num_words > max_words)
0079         num_words = max_words;
0080 
0081     for (count = 0; count < num_words; count++)
0082         ((u32 *)buf)[count] = rng_readl(priv, RNG_DATA);
0083 
0084     return num_words * sizeof(u32);
0085 }
0086 
0087 static int bcm2835_rng_init(struct hwrng *rng)
0088 {
0089     struct bcm2835_rng_priv *priv = to_rng_priv(rng);
0090     int ret = 0;
0091     u32 val;
0092 
0093     ret = clk_prepare_enable(priv->clk);
0094     if (ret)
0095         return ret;
0096 
0097     ret = reset_control_reset(priv->reset);
0098     if (ret)
0099         return ret;
0100 
0101     if (priv->mask_interrupts) {
0102         /* mask the interrupt */
0103         val = rng_readl(priv, RNG_INT_MASK);
0104         val |= RNG_INT_OFF;
0105         rng_writel(priv, val, RNG_INT_MASK);
0106     }
0107 
0108     /* set warm-up count & enable */
0109     rng_writel(priv, RNG_WARMUP_COUNT, RNG_STATUS);
0110     rng_writel(priv, RNG_RBGEN, RNG_CTRL);
0111 
0112     return ret;
0113 }
0114 
0115 static void bcm2835_rng_cleanup(struct hwrng *rng)
0116 {
0117     struct bcm2835_rng_priv *priv = to_rng_priv(rng);
0118 
0119     /* disable rng hardware */
0120     rng_writel(priv, 0, RNG_CTRL);
0121 
0122     clk_disable_unprepare(priv->clk);
0123 }
0124 
0125 struct bcm2835_rng_of_data {
0126     bool mask_interrupts;
0127 };
0128 
0129 static const struct bcm2835_rng_of_data nsp_rng_of_data = {
0130     .mask_interrupts = true,
0131 };
0132 
0133 static const struct of_device_id bcm2835_rng_of_match[] = {
0134     { .compatible = "brcm,bcm2835-rng"},
0135     { .compatible = "brcm,bcm-nsp-rng", .data = &nsp_rng_of_data },
0136     { .compatible = "brcm,bcm5301x-rng", .data = &nsp_rng_of_data },
0137     { .compatible = "brcm,bcm6368-rng"},
0138     {},
0139 };
0140 
0141 static int bcm2835_rng_probe(struct platform_device *pdev)
0142 {
0143     const struct bcm2835_rng_of_data *of_data;
0144     struct device *dev = &pdev->dev;
0145     const struct of_device_id *rng_id;
0146     struct bcm2835_rng_priv *priv;
0147     int err;
0148 
0149     priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0150     if (!priv)
0151         return -ENOMEM;
0152 
0153     platform_set_drvdata(pdev, priv);
0154 
0155     /* map peripheral */
0156     priv->base = devm_platform_ioremap_resource(pdev, 0);
0157     if (IS_ERR(priv->base))
0158         return PTR_ERR(priv->base);
0159 
0160     /* Clock is optional on most platforms */
0161     priv->clk = devm_clk_get_optional(dev, NULL);
0162     if (IS_ERR(priv->clk))
0163         return PTR_ERR(priv->clk);
0164 
0165     priv->reset = devm_reset_control_get_optional_exclusive(dev, NULL);
0166     if (IS_ERR(priv->reset))
0167         return PTR_ERR(priv->reset);
0168 
0169     priv->rng.name = pdev->name;
0170     priv->rng.init = bcm2835_rng_init;
0171     priv->rng.read = bcm2835_rng_read;
0172     priv->rng.cleanup = bcm2835_rng_cleanup;
0173 
0174     if (dev_of_node(dev)) {
0175         rng_id = of_match_node(bcm2835_rng_of_match, dev->of_node);
0176         if (!rng_id)
0177             return -EINVAL;
0178 
0179         /* Check for rng init function, execute it */
0180         of_data = rng_id->data;
0181         if (of_data)
0182             priv->mask_interrupts = of_data->mask_interrupts;
0183     }
0184 
0185     /* register driver */
0186     err = devm_hwrng_register(dev, &priv->rng);
0187     if (err)
0188         dev_err(dev, "hwrng registration failed\n");
0189     else
0190         dev_info(dev, "hwrng registered\n");
0191 
0192     return err;
0193 }
0194 
0195 MODULE_DEVICE_TABLE(of, bcm2835_rng_of_match);
0196 
0197 static const struct platform_device_id bcm2835_rng_devtype[] = {
0198     { .name = "bcm2835-rng" },
0199     { .name = "bcm63xx-rng" },
0200     { /* sentinel */ }
0201 };
0202 MODULE_DEVICE_TABLE(platform, bcm2835_rng_devtype);
0203 
0204 static struct platform_driver bcm2835_rng_driver = {
0205     .driver = {
0206         .name = "bcm2835-rng",
0207         .of_match_table = bcm2835_rng_of_match,
0208     },
0209     .probe      = bcm2835_rng_probe,
0210     .id_table   = bcm2835_rng_devtype,
0211 };
0212 module_platform_driver(bcm2835_rng_driver);
0213 
0214 MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>");
0215 MODULE_DESCRIPTION("BCM2835 Random Number Generator (RNG) driver");
0216 MODULE_LICENSE("GPL v2");