0001
0002
0003
0004
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
0024 #define RNG_RBGEN 0x1
0025
0026
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
0047
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
0103 val = rng_readl(priv, RNG_INT_MASK);
0104 val |= RNG_INT_OFF;
0105 rng_writel(priv, val, RNG_INT_MASK);
0106 }
0107
0108
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
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
0156 priv->base = devm_platform_ioremap_resource(pdev, 0);
0157 if (IS_ERR(priv->base))
0158 return PTR_ERR(priv->base);
0159
0160
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
0180 of_data = rng_id->data;
0181 if (of_data)
0182 priv->mask_interrupts = of_data->mask_interrupts;
0183 }
0184
0185
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 { }
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");