• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Broadcom BCM63xx Random Number Generator support
3  *
4  * Copyright (C) 2011, Florian Fainelli <florian@openwrt.org>
5  * Copyright (C) 2009, Broadcom Corporation
6  *
7  */
8 #include <linux/module.h>
9 #include <linux/slab.h>
10 #include <linux/io.h>
11 #include <linux/err.h>
12 #include <linux/clk.h>
13 #include <linux/platform_device.h>
14 #include <linux/hw_random.h>
15 #include <linux/of.h>
16 
17 #define RNG_CTRL			0x00
18 #define RNG_EN				(1 << 0)
19 
20 #define RNG_STAT			0x04
21 #define RNG_AVAIL_MASK			(0xff000000)
22 
23 #define RNG_DATA			0x08
24 #define RNG_THRES			0x0c
25 #define RNG_MASK			0x10
26 
27 struct bcm63xx_rng_priv {
28 	struct hwrng rng;
29 	struct clk *clk;
30 	void __iomem *regs;
31 };
32 
33 #define to_rng_priv(rng)	container_of(rng, struct bcm63xx_rng_priv, rng)
34 
bcm63xx_rng_init(struct hwrng * rng)35 static int bcm63xx_rng_init(struct hwrng *rng)
36 {
37 	struct bcm63xx_rng_priv *priv = to_rng_priv(rng);
38 	u32 val;
39 	int error;
40 
41 	error = clk_prepare_enable(priv->clk);
42 	if (error)
43 		return error;
44 
45 	val = __raw_readl(priv->regs + RNG_CTRL);
46 	val |= RNG_EN;
47 	__raw_writel(val, priv->regs + RNG_CTRL);
48 
49 	return 0;
50 }
51 
bcm63xx_rng_cleanup(struct hwrng * rng)52 static void bcm63xx_rng_cleanup(struct hwrng *rng)
53 {
54 	struct bcm63xx_rng_priv *priv = to_rng_priv(rng);
55 	u32 val;
56 
57 	val = __raw_readl(priv->regs + RNG_CTRL);
58 	val &= ~RNG_EN;
59 	__raw_writel(val, priv->regs + RNG_CTRL);
60 
61 	clk_disable_unprepare(priv->clk);
62 }
63 
bcm63xx_rng_data_present(struct hwrng * rng,int wait)64 static int bcm63xx_rng_data_present(struct hwrng *rng, int wait)
65 {
66 	struct bcm63xx_rng_priv *priv = to_rng_priv(rng);
67 
68 	return __raw_readl(priv->regs + RNG_STAT) & RNG_AVAIL_MASK;
69 }
70 
bcm63xx_rng_data_read(struct hwrng * rng,u32 * data)71 static int bcm63xx_rng_data_read(struct hwrng *rng, u32 *data)
72 {
73 	struct bcm63xx_rng_priv *priv = to_rng_priv(rng);
74 
75 	*data = __raw_readl(priv->regs + RNG_DATA);
76 
77 	return 4;
78 }
79 
bcm63xx_rng_probe(struct platform_device * pdev)80 static int bcm63xx_rng_probe(struct platform_device *pdev)
81 {
82 	struct resource *r;
83 	int ret;
84 	struct bcm63xx_rng_priv *priv;
85 
86 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
87 	if (!r) {
88 		dev_err(&pdev->dev, "no iomem resource\n");
89 		return -ENXIO;
90 	}
91 
92 	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
93 	if (!priv)
94 		return -ENOMEM;
95 
96 	priv->rng.name = pdev->name;
97 	priv->rng.init = bcm63xx_rng_init;
98 	priv->rng.cleanup = bcm63xx_rng_cleanup;
99 	priv->rng.data_present = bcm63xx_rng_data_present;
100 	priv->rng.data_read = bcm63xx_rng_data_read;
101 
102 	priv->clk = devm_clk_get(&pdev->dev, "ipsec");
103 	if (IS_ERR(priv->clk)) {
104 		ret = PTR_ERR(priv->clk);
105 		dev_err(&pdev->dev, "no clock for device: %d\n", ret);
106 		return ret;
107 	}
108 
109 	if (!devm_request_mem_region(&pdev->dev, r->start,
110 					resource_size(r), pdev->name)) {
111 		dev_err(&pdev->dev, "request mem failed");
112 		return -EBUSY;
113 	}
114 
115 	priv->regs = devm_ioremap_nocache(&pdev->dev, r->start,
116 					resource_size(r));
117 	if (!priv->regs) {
118 		dev_err(&pdev->dev, "ioremap failed");
119 		return -ENOMEM;
120 	}
121 
122 	ret = devm_hwrng_register(&pdev->dev, &priv->rng);
123 	if (ret) {
124 		dev_err(&pdev->dev, "failed to register rng device: %d\n",
125 			ret);
126 		return ret;
127 	}
128 
129 	dev_info(&pdev->dev, "registered RNG driver\n");
130 
131 	return 0;
132 }
133 
134 #ifdef CONFIG_OF
135 static const struct of_device_id bcm63xx_rng_of_match[] = {
136 	{ .compatible = "brcm,bcm6368-rng", },
137 	{},
138 };
139 MODULE_DEVICE_TABLE(of, bcm63xx_rng_of_match);
140 #endif
141 
142 static struct platform_driver bcm63xx_rng_driver = {
143 	.probe		= bcm63xx_rng_probe,
144 	.driver		= {
145 		.name	= "bcm63xx-rng",
146 		.of_match_table = of_match_ptr(bcm63xx_rng_of_match),
147 	},
148 };
149 
150 module_platform_driver(bcm63xx_rng_driver);
151 
152 MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
153 MODULE_DESCRIPTION("Broadcom BCM63xx RNG driver");
154 MODULE_LICENSE("GPL");
155