1 | /* |
2 | * Hardware Random Number Generator support for Cavium Networks |
3 | * Octeon processor family. |
4 | * |
5 | * This file is subject to the terms and conditions of the GNU General Public |
6 | * License. See the file "COPYING" in the main directory of this archive |
7 | * for more details. |
8 | * |
9 | * Copyright (C) 2009 Cavium Networks |
10 | */ |
11 | |
12 | #include <linux/module.h> |
13 | #include <linux/platform_device.h> |
14 | #include <linux/device.h> |
15 | #include <linux/hw_random.h> |
16 | #include <linux/io.h> |
17 | #include <linux/gfp.h> |
18 | |
19 | #include <asm/octeon/octeon.h> |
20 | #include <asm/octeon/cvmx-rnm-defs.h> |
21 | |
22 | struct octeon_rng { |
23 | struct hwrng ops; |
24 | void __iomem *control_status; |
25 | void __iomem *result; |
26 | }; |
27 | |
28 | static int octeon_rng_init(struct hwrng *rng) |
29 | { |
30 | union cvmx_rnm_ctl_status ctl; |
31 | struct octeon_rng *p = container_of(rng, struct octeon_rng, ops); |
32 | |
33 | ctl.u64 = 0; |
34 | ctl.s.ent_en = 1; /* Enable the entropy source. */ |
35 | ctl.s.rng_en = 1; /* Enable the RNG hardware. */ |
36 | cvmx_write_csr((unsigned long)p->control_status, ctl.u64); |
37 | return 0; |
38 | } |
39 | |
40 | static void octeon_rng_cleanup(struct hwrng *rng) |
41 | { |
42 | union cvmx_rnm_ctl_status ctl; |
43 | struct octeon_rng *p = container_of(rng, struct octeon_rng, ops); |
44 | |
45 | ctl.u64 = 0; |
46 | /* Disable everything. */ |
47 | cvmx_write_csr((unsigned long)p->control_status, ctl.u64); |
48 | } |
49 | |
50 | static int octeon_rng_data_read(struct hwrng *rng, u32 *data) |
51 | { |
52 | struct octeon_rng *p = container_of(rng, struct octeon_rng, ops); |
53 | |
54 | *data = cvmx_read64_uint32((unsigned long)p->result); |
55 | return sizeof(u32); |
56 | } |
57 | |
58 | static int octeon_rng_probe(struct platform_device *pdev) |
59 | { |
60 | struct resource *res_ports; |
61 | struct resource *res_result; |
62 | struct octeon_rng *rng; |
63 | int ret; |
64 | struct hwrng ops = { |
65 | .name = "octeon" , |
66 | .init = octeon_rng_init, |
67 | .cleanup = octeon_rng_cleanup, |
68 | .data_read = octeon_rng_data_read |
69 | }; |
70 | |
71 | rng = devm_kzalloc(dev: &pdev->dev, size: sizeof(*rng), GFP_KERNEL); |
72 | if (!rng) |
73 | return -ENOMEM; |
74 | |
75 | res_ports = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
76 | if (!res_ports) |
77 | return -ENOENT; |
78 | |
79 | res_result = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
80 | if (!res_result) |
81 | return -ENOENT; |
82 | |
83 | |
84 | rng->control_status = devm_ioremap(dev: &pdev->dev, |
85 | offset: res_ports->start, |
86 | size: sizeof(u64)); |
87 | if (!rng->control_status) |
88 | return -ENOENT; |
89 | |
90 | rng->result = devm_ioremap(dev: &pdev->dev, |
91 | offset: res_result->start, |
92 | size: sizeof(u64)); |
93 | if (!rng->result) |
94 | return -ENOENT; |
95 | |
96 | rng->ops = ops; |
97 | |
98 | platform_set_drvdata(pdev, data: &rng->ops); |
99 | ret = devm_hwrng_register(dev: &pdev->dev, rng: &rng->ops); |
100 | if (ret) |
101 | return -ENOENT; |
102 | |
103 | dev_info(&pdev->dev, "Octeon Random Number Generator\n" ); |
104 | |
105 | return 0; |
106 | } |
107 | |
108 | static struct platform_driver octeon_rng_driver = { |
109 | .driver = { |
110 | .name = "octeon_rng" , |
111 | }, |
112 | .probe = octeon_rng_probe, |
113 | }; |
114 | |
115 | module_platform_driver(octeon_rng_driver); |
116 | |
117 | MODULE_AUTHOR("David Daney" ); |
118 | MODULE_LICENSE("GPL" ); |
119 | |