1 /** 2 * Copyright (c) 2010-2012 Broadcom. All rights reserved. 3 * Copyright (c) 2013 Lubomir Rintel 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License ("GPL") 7 * version 2, as published by the Free Software Foundation. 8 */ 9 10 #include <linux/hw_random.h> 11 #include <linux/io.h> 12 #include <linux/kernel.h> 13 #include <linux/module.h> 14 #include <linux/of_address.h> 15 #include <linux/of_platform.h> 16 #include <linux/platform_device.h> 17 #include <linux/printk.h> 18 19 #define RNG_CTRL 0x0 20 #define RNG_STATUS 0x4 21 #define RNG_DATA 0x8 22 #define RNG_INT_MASK 0x10 23 24 /* enable rng */ 25 #define RNG_RBGEN 0x1 26 27 /* the initial numbers generated are "less random" so will be discarded */ 28 #define RNG_WARMUP_COUNT 0x40000 29 30 #define RNG_INT_OFF 0x1 31 32 static void __init nsp_rng_init(void __iomem *base) 33 { 34 u32 val; 35 36 /* mask the interrupt */ 37 val = readl(base + RNG_INT_MASK); 38 val |= RNG_INT_OFF; 39 writel(val, base + RNG_INT_MASK); 40 } 41 42 static int bcm2835_rng_read(struct hwrng *rng, void *buf, size_t max, 43 bool wait) 44 { 45 void __iomem *rng_base = (void __iomem *)rng->priv; 46 u32 max_words = max / sizeof(u32); 47 u32 num_words, count; 48 49 while ((__raw_readl(rng_base + RNG_STATUS) >> 24) == 0) { 50 if (!wait) 51 return 0; 52 cpu_relax(); 53 } 54 55 num_words = readl(rng_base + RNG_STATUS) >> 24; 56 if (num_words > max_words) 57 num_words = max_words; 58 59 for (count = 0; count < num_words; count++) 60 ((u32 *)buf)[count] = readl(rng_base + RNG_DATA); 61 62 return num_words * sizeof(u32); 63 } 64 65 static struct hwrng bcm2835_rng_ops = { 66 .name = "bcm2835", 67 .read = bcm2835_rng_read, 68 }; 69 70 static const struct of_device_id bcm2835_rng_of_match[] = { 71 { .compatible = "brcm,bcm2835-rng"}, 72 { .compatible = "brcm,bcm-nsp-rng", .data = nsp_rng_init}, 73 { .compatible = "brcm,bcm5301x-rng", .data = nsp_rng_init}, 74 {}, 75 }; 76 77 static int bcm2835_rng_probe(struct platform_device *pdev) 78 { 79 struct device *dev = &pdev->dev; 80 struct device_node *np = dev->of_node; 81 void (*rng_setup)(void __iomem *base); 82 const struct of_device_id *rng_id; 83 void __iomem *rng_base; 84 int err; 85 86 /* map peripheral */ 87 rng_base = of_iomap(np, 0); 88 if (!rng_base) { 89 dev_err(dev, "failed to remap rng regs"); 90 return -ENODEV; 91 } 92 bcm2835_rng_ops.priv = (unsigned long)rng_base; 93 94 rng_id = of_match_node(bcm2835_rng_of_match, np); 95 if (!rng_id) { 96 iounmap(rng_base); 97 return -EINVAL; 98 } 99 /* Check for rng init function, execute it */ 100 rng_setup = rng_id->data; 101 if (rng_setup) 102 rng_setup(rng_base); 103 104 /* set warm-up count & enable */ 105 __raw_writel(RNG_WARMUP_COUNT, rng_base + RNG_STATUS); 106 __raw_writel(RNG_RBGEN, rng_base + RNG_CTRL); 107 108 /* register driver */ 109 err = hwrng_register(&bcm2835_rng_ops); 110 if (err) { 111 dev_err(dev, "hwrng registration failed\n"); 112 iounmap(rng_base); 113 } else 114 dev_info(dev, "hwrng registered\n"); 115 116 return err; 117 } 118 119 static int bcm2835_rng_remove(struct platform_device *pdev) 120 { 121 void __iomem *rng_base = (void __iomem *)bcm2835_rng_ops.priv; 122 123 /* disable rng hardware */ 124 __raw_writel(0, rng_base + RNG_CTRL); 125 126 /* unregister driver */ 127 hwrng_unregister(&bcm2835_rng_ops); 128 iounmap(rng_base); 129 130 return 0; 131 } 132 133 MODULE_DEVICE_TABLE(of, bcm2835_rng_of_match); 134 135 static struct platform_driver bcm2835_rng_driver = { 136 .driver = { 137 .name = "bcm2835-rng", 138 .of_match_table = bcm2835_rng_of_match, 139 }, 140 .probe = bcm2835_rng_probe, 141 .remove = bcm2835_rng_remove, 142 }; 143 module_platform_driver(bcm2835_rng_driver); 144 145 MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>"); 146 MODULE_DESCRIPTION("BCM2835 Random Number Generator (RNG) driver"); 147 MODULE_LICENSE("GPL v2"); 148