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