xref: /openbmc/linux/drivers/char/hw_random/bcm2835-rng.c (revision 8c4196a2fd7c31acd6d02d9921f7896b8f160c92)
1*8c4196a2SLubomir Rintel /**
2*8c4196a2SLubomir Rintel  * Copyright (c) 2010-2012 Broadcom. All rights reserved.
3*8c4196a2SLubomir Rintel  * Copyright (c) 2013 Lubomir Rintel
4*8c4196a2SLubomir Rintel  *
5*8c4196a2SLubomir Rintel  * This program is free software; you can redistribute it and/or
6*8c4196a2SLubomir Rintel  * modify it under the terms of the GNU General Public License ("GPL")
7*8c4196a2SLubomir Rintel  * version 2, as published by the Free Software Foundation.
8*8c4196a2SLubomir Rintel  */
9*8c4196a2SLubomir Rintel 
10*8c4196a2SLubomir Rintel #include <linux/hw_random.h>
11*8c4196a2SLubomir Rintel #include <linux/init.h>
12*8c4196a2SLubomir Rintel #include <linux/io.h>
13*8c4196a2SLubomir Rintel #include <linux/kernel.h>
14*8c4196a2SLubomir Rintel #include <linux/module.h>
15*8c4196a2SLubomir Rintel #include <linux/of_address.h>
16*8c4196a2SLubomir Rintel #include <linux/of_platform.h>
17*8c4196a2SLubomir Rintel #include <linux/platform_device.h>
18*8c4196a2SLubomir Rintel #include <linux/printk.h>
19*8c4196a2SLubomir Rintel 
20*8c4196a2SLubomir Rintel #define RNG_CTRL	0x0
21*8c4196a2SLubomir Rintel #define RNG_STATUS	0x4
22*8c4196a2SLubomir Rintel #define RNG_DATA	0x8
23*8c4196a2SLubomir Rintel 
24*8c4196a2SLubomir Rintel /* enable rng */
25*8c4196a2SLubomir Rintel #define RNG_RBGEN	0x1
26*8c4196a2SLubomir Rintel 
27*8c4196a2SLubomir Rintel /* the initial numbers generated are "less random" so will be discarded */
28*8c4196a2SLubomir Rintel #define RNG_WARMUP_COUNT 0x40000
29*8c4196a2SLubomir Rintel 
30*8c4196a2SLubomir Rintel static int bcm2835_rng_read(struct hwrng *rng, void *buf, size_t max,
31*8c4196a2SLubomir Rintel 			       bool wait)
32*8c4196a2SLubomir Rintel {
33*8c4196a2SLubomir Rintel 	void __iomem *rng_base = (void __iomem *)rng->priv;
34*8c4196a2SLubomir Rintel 
35*8c4196a2SLubomir Rintel 	while ((__raw_readl(rng_base + RNG_STATUS) >> 24) == 0) {
36*8c4196a2SLubomir Rintel 		if (!wait)
37*8c4196a2SLubomir Rintel 			return 0;
38*8c4196a2SLubomir Rintel 		cpu_relax();
39*8c4196a2SLubomir Rintel 	}
40*8c4196a2SLubomir Rintel 
41*8c4196a2SLubomir Rintel 	*(u32 *)buf = __raw_readl(rng_base + RNG_DATA);
42*8c4196a2SLubomir Rintel 	return sizeof(u32);
43*8c4196a2SLubomir Rintel }
44*8c4196a2SLubomir Rintel 
45*8c4196a2SLubomir Rintel static struct hwrng bcm2835_rng_ops = {
46*8c4196a2SLubomir Rintel 	.name	= "bcm2835",
47*8c4196a2SLubomir Rintel 	.read	= bcm2835_rng_read,
48*8c4196a2SLubomir Rintel };
49*8c4196a2SLubomir Rintel 
50*8c4196a2SLubomir Rintel static int bcm2835_rng_probe(struct platform_device *pdev)
51*8c4196a2SLubomir Rintel {
52*8c4196a2SLubomir Rintel 	struct device *dev = &pdev->dev;
53*8c4196a2SLubomir Rintel 	struct device_node *np = dev->of_node;
54*8c4196a2SLubomir Rintel 	void __iomem *rng_base;
55*8c4196a2SLubomir Rintel 	int err;
56*8c4196a2SLubomir Rintel 
57*8c4196a2SLubomir Rintel 	/* map peripheral */
58*8c4196a2SLubomir Rintel 	rng_base = of_iomap(np, 0);
59*8c4196a2SLubomir Rintel 	if (!rng_base) {
60*8c4196a2SLubomir Rintel 		dev_err(dev, "failed to remap rng regs");
61*8c4196a2SLubomir Rintel 		return -ENODEV;
62*8c4196a2SLubomir Rintel 	}
63*8c4196a2SLubomir Rintel 	bcm2835_rng_ops.priv = (unsigned long)rng_base;
64*8c4196a2SLubomir Rintel 
65*8c4196a2SLubomir Rintel 	/* register driver */
66*8c4196a2SLubomir Rintel 	err = hwrng_register(&bcm2835_rng_ops);
67*8c4196a2SLubomir Rintel 	if (err) {
68*8c4196a2SLubomir Rintel 		dev_err(dev, "hwrng registration failed\n");
69*8c4196a2SLubomir Rintel 		iounmap(rng_base);
70*8c4196a2SLubomir Rintel 	} else {
71*8c4196a2SLubomir Rintel 		dev_info(dev, "hwrng registered\n");
72*8c4196a2SLubomir Rintel 
73*8c4196a2SLubomir Rintel 		/* set warm-up count & enable */
74*8c4196a2SLubomir Rintel 		__raw_writel(RNG_WARMUP_COUNT, rng_base + RNG_STATUS);
75*8c4196a2SLubomir Rintel 		__raw_writel(RNG_RBGEN, rng_base + RNG_CTRL);
76*8c4196a2SLubomir Rintel 	}
77*8c4196a2SLubomir Rintel 	return err;
78*8c4196a2SLubomir Rintel }
79*8c4196a2SLubomir Rintel 
80*8c4196a2SLubomir Rintel static int bcm2835_rng_remove(struct platform_device *pdev)
81*8c4196a2SLubomir Rintel {
82*8c4196a2SLubomir Rintel 	void __iomem *rng_base = (void __iomem *)bcm2835_rng_ops.priv;
83*8c4196a2SLubomir Rintel 
84*8c4196a2SLubomir Rintel 	/* disable rng hardware */
85*8c4196a2SLubomir Rintel 	__raw_writel(0, rng_base + RNG_CTRL);
86*8c4196a2SLubomir Rintel 
87*8c4196a2SLubomir Rintel 	/* unregister driver */
88*8c4196a2SLubomir Rintel 	hwrng_unregister(&bcm2835_rng_ops);
89*8c4196a2SLubomir Rintel 	iounmap(rng_base);
90*8c4196a2SLubomir Rintel 
91*8c4196a2SLubomir Rintel 	return 0;
92*8c4196a2SLubomir Rintel }
93*8c4196a2SLubomir Rintel 
94*8c4196a2SLubomir Rintel static const struct of_device_id bcm2835_rng_of_match[] = {
95*8c4196a2SLubomir Rintel 	{ .compatible = "brcm,bcm2835-rng", },
96*8c4196a2SLubomir Rintel 	{},
97*8c4196a2SLubomir Rintel };
98*8c4196a2SLubomir Rintel MODULE_DEVICE_TABLE(of, bcm2835_rng_of_match);
99*8c4196a2SLubomir Rintel 
100*8c4196a2SLubomir Rintel static struct platform_driver bcm2835_rng_driver = {
101*8c4196a2SLubomir Rintel 	.driver = {
102*8c4196a2SLubomir Rintel 		.name = "bcm2835-rng",
103*8c4196a2SLubomir Rintel 		.owner = THIS_MODULE,
104*8c4196a2SLubomir Rintel 		.of_match_table = bcm2835_rng_of_match,
105*8c4196a2SLubomir Rintel 	},
106*8c4196a2SLubomir Rintel 	.probe		= bcm2835_rng_probe,
107*8c4196a2SLubomir Rintel 	.remove		= bcm2835_rng_remove,
108*8c4196a2SLubomir Rintel };
109*8c4196a2SLubomir Rintel module_platform_driver(bcm2835_rng_driver);
110*8c4196a2SLubomir Rintel 
111*8c4196a2SLubomir Rintel MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>");
112*8c4196a2SLubomir Rintel MODULE_DESCRIPTION("BCM2835 Random Number Generator (RNG) driver");
113*8c4196a2SLubomir Rintel MODULE_LICENSE("GPLv2");
114