xref: /linux/drivers/char/hw_random/mxc-rnga.c (revision bd628c1bed7902ec1f24ba0fe70758949146abbe)
1 /*
2  * RNG driver for Freescale RNGA
3  *
4  * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
5  * Author: Alan Carvalho de Assis <acassis@gmail.com>
6  */
7 
8 /*
9  * The code contained herein is licensed under the GNU General Public
10  * License. You may obtain a copy of the GNU General Public License
11  * Version 2 or later at the following locations:
12  *
13  * http://www.opensource.org/licenses/gpl-license.html
14  * http://www.gnu.org/copyleft/gpl.html
15  *
16  * This driver is based on other RNG drivers.
17  */
18 
19 #include <linux/clk.h>
20 #include <linux/delay.h>
21 #include <linux/hw_random.h>
22 #include <linux/io.h>
23 #include <linux/module.h>
24 #include <linux/of.h>
25 #include <linux/platform_device.h>
26 
27 /* RNGA Registers */
28 #define RNGA_CONTROL			0x00
29 #define RNGA_STATUS			0x04
30 #define RNGA_ENTROPY			0x08
31 #define RNGA_OUTPUT_FIFO		0x0c
32 #define RNGA_MODE			0x10
33 #define RNGA_VERIFICATION_CONTROL	0x14
34 #define RNGA_OSC_CONTROL_COUNTER	0x18
35 #define RNGA_OSC1_COUNTER		0x1c
36 #define RNGA_OSC2_COUNTER		0x20
37 #define RNGA_OSC_COUNTER_STATUS		0x24
38 
39 /* RNGA Registers Range */
40 #define RNG_ADDR_RANGE			0x28
41 
42 /* RNGA Control Register */
43 #define RNGA_CONTROL_SLEEP		0x00000010
44 #define RNGA_CONTROL_CLEAR_INT		0x00000008
45 #define RNGA_CONTROL_MASK_INTS		0x00000004
46 #define RNGA_CONTROL_HIGH_ASSURANCE	0x00000002
47 #define RNGA_CONTROL_GO			0x00000001
48 
49 #define RNGA_STATUS_LEVEL_MASK		0x0000ff00
50 
51 /* RNGA Status Register */
52 #define RNGA_STATUS_OSC_DEAD		0x80000000
53 #define RNGA_STATUS_SLEEP		0x00000010
54 #define RNGA_STATUS_ERROR_INT		0x00000008
55 #define RNGA_STATUS_FIFO_UNDERFLOW	0x00000004
56 #define RNGA_STATUS_LAST_READ_STATUS	0x00000002
57 #define RNGA_STATUS_SECURITY_VIOLATION	0x00000001
58 
59 struct mxc_rng {
60 	struct device *dev;
61 	struct hwrng rng;
62 	void __iomem *mem;
63 	struct clk *clk;
64 };
65 
66 static int mxc_rnga_data_present(struct hwrng *rng, int wait)
67 {
68 	int i;
69 	struct mxc_rng *mxc_rng = container_of(rng, struct mxc_rng, rng);
70 
71 	for (i = 0; i < 20; i++) {
72 		/* how many random numbers are in FIFO? [0-16] */
73 		int level = (__raw_readl(mxc_rng->mem + RNGA_STATUS) &
74 				RNGA_STATUS_LEVEL_MASK) >> 8;
75 		if (level || !wait)
76 			return !!level;
77 		udelay(10);
78 	}
79 	return 0;
80 }
81 
82 static int mxc_rnga_data_read(struct hwrng *rng, u32 * data)
83 {
84 	int err;
85 	u32 ctrl;
86 	struct mxc_rng *mxc_rng = container_of(rng, struct mxc_rng, rng);
87 
88 	/* retrieve a random number from FIFO */
89 	*data = __raw_readl(mxc_rng->mem + RNGA_OUTPUT_FIFO);
90 
91 	/* some error while reading this random number? */
92 	err = __raw_readl(mxc_rng->mem + RNGA_STATUS) & RNGA_STATUS_ERROR_INT;
93 
94 	/* if error: clear error interrupt, but doesn't return random number */
95 	if (err) {
96 		dev_dbg(mxc_rng->dev, "Error while reading random number!\n");
97 		ctrl = __raw_readl(mxc_rng->mem + RNGA_CONTROL);
98 		__raw_writel(ctrl | RNGA_CONTROL_CLEAR_INT,
99 					mxc_rng->mem + RNGA_CONTROL);
100 		return 0;
101 	} else
102 		return 4;
103 }
104 
105 static int mxc_rnga_init(struct hwrng *rng)
106 {
107 	u32 ctrl, osc;
108 	struct mxc_rng *mxc_rng = container_of(rng, struct mxc_rng, rng);
109 
110 	/* wake up */
111 	ctrl = __raw_readl(mxc_rng->mem + RNGA_CONTROL);
112 	__raw_writel(ctrl & ~RNGA_CONTROL_SLEEP, mxc_rng->mem + RNGA_CONTROL);
113 
114 	/* verify if oscillator is working */
115 	osc = __raw_readl(mxc_rng->mem + RNGA_STATUS);
116 	if (osc & RNGA_STATUS_OSC_DEAD) {
117 		dev_err(mxc_rng->dev, "RNGA Oscillator is dead!\n");
118 		return -ENODEV;
119 	}
120 
121 	/* go running */
122 	ctrl = __raw_readl(mxc_rng->mem + RNGA_CONTROL);
123 	__raw_writel(ctrl | RNGA_CONTROL_GO, mxc_rng->mem + RNGA_CONTROL);
124 
125 	return 0;
126 }
127 
128 static void mxc_rnga_cleanup(struct hwrng *rng)
129 {
130 	u32 ctrl;
131 	struct mxc_rng *mxc_rng = container_of(rng, struct mxc_rng, rng);
132 
133 	ctrl = __raw_readl(mxc_rng->mem + RNGA_CONTROL);
134 
135 	/* stop rnga */
136 	__raw_writel(ctrl & ~RNGA_CONTROL_GO, mxc_rng->mem + RNGA_CONTROL);
137 }
138 
139 static int __init mxc_rnga_probe(struct platform_device *pdev)
140 {
141 	int err;
142 	struct resource *res;
143 	struct mxc_rng *mxc_rng;
144 
145 	mxc_rng = devm_kzalloc(&pdev->dev, sizeof(*mxc_rng), GFP_KERNEL);
146 	if (!mxc_rng)
147 		return -ENOMEM;
148 
149 	mxc_rng->dev = &pdev->dev;
150 	mxc_rng->rng.name = "mxc-rnga";
151 	mxc_rng->rng.init = mxc_rnga_init;
152 	mxc_rng->rng.cleanup = mxc_rnga_cleanup,
153 	mxc_rng->rng.data_present = mxc_rnga_data_present,
154 	mxc_rng->rng.data_read = mxc_rnga_data_read,
155 
156 	mxc_rng->clk = devm_clk_get(&pdev->dev, NULL);
157 	if (IS_ERR(mxc_rng->clk)) {
158 		dev_err(&pdev->dev, "Could not get rng_clk!\n");
159 		return PTR_ERR(mxc_rng->clk);
160 	}
161 
162 	err = clk_prepare_enable(mxc_rng->clk);
163 	if (err)
164 		return err;
165 
166 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
167 	mxc_rng->mem = devm_ioremap_resource(&pdev->dev, res);
168 	if (IS_ERR(mxc_rng->mem)) {
169 		err = PTR_ERR(mxc_rng->mem);
170 		goto err_ioremap;
171 	}
172 
173 	err = hwrng_register(&mxc_rng->rng);
174 	if (err) {
175 		dev_err(&pdev->dev, "MXC RNGA registering failed (%d)\n", err);
176 		goto err_ioremap;
177 	}
178 
179 	return 0;
180 
181 err_ioremap:
182 	clk_disable_unprepare(mxc_rng->clk);
183 	return err;
184 }
185 
186 static int __exit mxc_rnga_remove(struct platform_device *pdev)
187 {
188 	struct mxc_rng *mxc_rng = platform_get_drvdata(pdev);
189 
190 	hwrng_unregister(&mxc_rng->rng);
191 
192 	clk_disable_unprepare(mxc_rng->clk);
193 
194 	return 0;
195 }
196 
197 static const struct of_device_id mxc_rnga_of_match[] = {
198 	{ .compatible = "fsl,imx21-rnga", },
199 	{ .compatible = "fsl,imx31-rnga", },
200 	{ /* sentinel */ },
201 };
202 MODULE_DEVICE_TABLE(of, mxc_rnga_of_match);
203 
204 static struct platform_driver mxc_rnga_driver = {
205 	.driver = {
206 		.name = "mxc_rnga",
207 		.of_match_table = mxc_rnga_of_match,
208 	},
209 	.remove = __exit_p(mxc_rnga_remove),
210 };
211 
212 module_platform_driver_probe(mxc_rnga_driver, mxc_rnga_probe);
213 
214 MODULE_AUTHOR("Freescale Semiconductor, Inc.");
215 MODULE_DESCRIPTION("H/W RNGA driver for i.MX");
216 MODULE_LICENSE("GPL");
217