0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/module.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/device.h>
0015 #include <linux/hw_random.h>
0016 #include <linux/io.h>
0017 #include <linux/gfp.h>
0018
0019 #include <asm/octeon/octeon.h>
0020 #include <asm/octeon/cvmx-rnm-defs.h>
0021
0022 struct octeon_rng {
0023 struct hwrng ops;
0024 void __iomem *control_status;
0025 void __iomem *result;
0026 };
0027
0028 static int octeon_rng_init(struct hwrng *rng)
0029 {
0030 union cvmx_rnm_ctl_status ctl;
0031 struct octeon_rng *p = container_of(rng, struct octeon_rng, ops);
0032
0033 ctl.u64 = 0;
0034 ctl.s.ent_en = 1;
0035 ctl.s.rng_en = 1;
0036 cvmx_write_csr((__force u64)p->control_status, ctl.u64);
0037 return 0;
0038 }
0039
0040 static void octeon_rng_cleanup(struct hwrng *rng)
0041 {
0042 union cvmx_rnm_ctl_status ctl;
0043 struct octeon_rng *p = container_of(rng, struct octeon_rng, ops);
0044
0045 ctl.u64 = 0;
0046
0047 cvmx_write_csr((__force u64)p->control_status, ctl.u64);
0048 }
0049
0050 static int octeon_rng_data_read(struct hwrng *rng, u32 *data)
0051 {
0052 struct octeon_rng *p = container_of(rng, struct octeon_rng, ops);
0053
0054 *data = cvmx_read64_uint32((__force u64)p->result);
0055 return sizeof(u32);
0056 }
0057
0058 static int octeon_rng_probe(struct platform_device *pdev)
0059 {
0060 struct resource *res_ports;
0061 struct resource *res_result;
0062 struct octeon_rng *rng;
0063 int ret;
0064 struct hwrng ops = {
0065 .name = "octeon",
0066 .init = octeon_rng_init,
0067 .cleanup = octeon_rng_cleanup,
0068 .data_read = octeon_rng_data_read
0069 };
0070
0071 rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL);
0072 if (!rng)
0073 return -ENOMEM;
0074
0075 res_ports = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0076 if (!res_ports)
0077 return -ENOENT;
0078
0079 res_result = platform_get_resource(pdev, IORESOURCE_MEM, 1);
0080 if (!res_result)
0081 return -ENOENT;
0082
0083
0084 rng->control_status = devm_ioremap(&pdev->dev,
0085 res_ports->start,
0086 sizeof(u64));
0087 if (!rng->control_status)
0088 return -ENOENT;
0089
0090 rng->result = devm_ioremap(&pdev->dev,
0091 res_result->start,
0092 sizeof(u64));
0093 if (!rng->result)
0094 return -ENOENT;
0095
0096 rng->ops = ops;
0097
0098 platform_set_drvdata(pdev, &rng->ops);
0099 ret = devm_hwrng_register(&pdev->dev, &rng->ops);
0100 if (ret)
0101 return -ENOENT;
0102
0103 dev_info(&pdev->dev, "Octeon Random Number Generator\n");
0104
0105 return 0;
0106 }
0107
0108 static struct platform_driver octeon_rng_driver = {
0109 .driver = {
0110 .name = "octeon_rng",
0111 },
0112 .probe = octeon_rng_probe,
0113 };
0114
0115 module_platform_driver(octeon_rng_driver);
0116
0117 MODULE_AUTHOR("David Daney");
0118 MODULE_LICENSE("GPL");