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 #include <linux/clk.h> 19 20 #define RNG_CTRL 0x0 21 #define RNG_STATUS 0x4 22 #define RNG_DATA 0x8 23 #define RNG_INT_MASK 0x10 24 25 /* enable rng */ 26 #define RNG_RBGEN 0x1 27 28 /* the initial numbers generated are "less random" so will be discarded */ 29 #define RNG_WARMUP_COUNT 0x40000 30 31 #define RNG_INT_OFF 0x1 32 33 struct bcm2835_rng_priv { 34 struct hwrng rng; 35 void __iomem *base; 36 bool mask_interrupts; 37 struct clk *clk; 38 }; 39 40 static inline struct bcm2835_rng_priv *to_rng_priv(struct hwrng *rng) 41 { 42 return container_of(rng, struct bcm2835_rng_priv, rng); 43 } 44 45 static inline u32 rng_readl(struct bcm2835_rng_priv *priv, u32 offset) 46 { 47 /* MIPS chips strapped for BE will automagically configure the 48 * peripheral registers for CPU-native byte order. 49 */ 50 if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) 51 return __raw_readl(priv->base + offset); 52 else 53 return readl(priv->base + offset); 54 } 55 56 static inline void rng_writel(struct bcm2835_rng_priv *priv, u32 val, 57 u32 offset) 58 { 59 if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) 60 __raw_writel(val, priv->base + offset); 61 else 62 writel(val, priv->base + offset); 63 } 64 65 static int bcm2835_rng_read(struct hwrng *rng, void *buf, size_t max, 66 bool wait) 67 { 68 struct bcm2835_rng_priv *priv = to_rng_priv(rng); 69 u32 max_words = max / sizeof(u32); 70 u32 num_words, count; 71 72 while ((rng_readl(priv, RNG_STATUS) >> 24) == 0) { 73 if (!wait) 74 return 0; 75 cpu_relax(); 76 } 77 78 num_words = rng_readl(priv, RNG_STATUS) >> 24; 79 if (num_words > max_words) 80 num_words = max_words; 81 82 for (count = 0; count < num_words; count++) 83 ((u32 *)buf)[count] = rng_readl(priv, RNG_DATA); 84 85 return num_words * sizeof(u32); 86 } 87 88 static int bcm2835_rng_init(struct hwrng *rng) 89 { 90 struct bcm2835_rng_priv *priv = to_rng_priv(rng); 91 int ret = 0; 92 u32 val; 93 94 if (!IS_ERR(priv->clk)) { 95 ret = clk_prepare_enable(priv->clk); 96 if (ret) 97 return ret; 98 } 99 100 if (priv->mask_interrupts) { 101 /* mask the interrupt */ 102 val = rng_readl(priv, RNG_INT_MASK); 103 val |= RNG_INT_OFF; 104 rng_writel(priv, val, RNG_INT_MASK); 105 } 106 107 /* set warm-up count & enable */ 108 rng_writel(priv, RNG_WARMUP_COUNT, RNG_STATUS); 109 rng_writel(priv, RNG_RBGEN, RNG_CTRL); 110 111 return ret; 112 } 113 114 static void bcm2835_rng_cleanup(struct hwrng *rng) 115 { 116 struct bcm2835_rng_priv *priv = to_rng_priv(rng); 117 118 /* disable rng hardware */ 119 rng_writel(priv, 0, RNG_CTRL); 120 121 if (!IS_ERR(priv->clk)) 122 clk_disable_unprepare(priv->clk); 123 } 124 125 struct bcm2835_rng_of_data { 126 bool mask_interrupts; 127 }; 128 129 static const struct bcm2835_rng_of_data nsp_rng_of_data = { 130 .mask_interrupts = true, 131 }; 132 133 static const struct of_device_id bcm2835_rng_of_match[] = { 134 { .compatible = "brcm,bcm2835-rng"}, 135 { .compatible = "brcm,bcm-nsp-rng", .data = &nsp_rng_of_data }, 136 { .compatible = "brcm,bcm5301x-rng", .data = &nsp_rng_of_data }, 137 { .compatible = "brcm,bcm6368-rng"}, 138 {}, 139 }; 140 141 static int bcm2835_rng_probe(struct platform_device *pdev) 142 { 143 const struct bcm2835_rng_of_data *of_data; 144 struct device *dev = &pdev->dev; 145 struct device_node *np = dev->of_node; 146 const struct of_device_id *rng_id; 147 struct bcm2835_rng_priv *priv; 148 struct resource *r; 149 int err; 150 151 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 152 if (!priv) 153 return -ENOMEM; 154 155 platform_set_drvdata(pdev, priv); 156 157 r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 158 159 /* map peripheral */ 160 priv->base = devm_ioremap_resource(dev, r); 161 if (IS_ERR(priv->base)) 162 return PTR_ERR(priv->base); 163 164 /* Clock is optional on most platforms */ 165 priv->clk = devm_clk_get(dev, NULL); 166 if (IS_ERR(priv->clk) && PTR_ERR(priv->clk) == -EPROBE_DEFER) 167 return -EPROBE_DEFER; 168 169 priv->rng.name = pdev->name; 170 priv->rng.init = bcm2835_rng_init; 171 priv->rng.read = bcm2835_rng_read; 172 priv->rng.cleanup = bcm2835_rng_cleanup; 173 174 rng_id = of_match_node(bcm2835_rng_of_match, np); 175 if (!rng_id) 176 return -EINVAL; 177 178 /* Check for rng init function, execute it */ 179 of_data = rng_id->data; 180 if (of_data) 181 priv->mask_interrupts = of_data->mask_interrupts; 182 183 /* register driver */ 184 err = devm_hwrng_register(dev, &priv->rng); 185 if (err) 186 dev_err(dev, "hwrng registration failed\n"); 187 else 188 dev_info(dev, "hwrng registered\n"); 189 190 return err; 191 } 192 193 MODULE_DEVICE_TABLE(of, bcm2835_rng_of_match); 194 195 static struct platform_device_id bcm2835_rng_devtype[] = { 196 { .name = "bcm2835-rng" }, 197 { .name = "bcm63xx-rng" }, 198 { /* sentinel */ } 199 }; 200 MODULE_DEVICE_TABLE(platform, bcm2835_rng_devtype); 201 202 static struct platform_driver bcm2835_rng_driver = { 203 .driver = { 204 .name = "bcm2835-rng", 205 .of_match_table = bcm2835_rng_of_match, 206 }, 207 .probe = bcm2835_rng_probe, 208 .id_table = bcm2835_rng_devtype, 209 }; 210 module_platform_driver(bcm2835_rng_driver); 211 212 MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>"); 213 MODULE_DESCRIPTION("BCM2835 Random Number Generator (RNG) driver"); 214 MODULE_LICENSE("GPL v2"); 215