Branch data Line data Source code
1 : : /* 2 : : * Copyright (C) 2015 Broadcom Corporation 3 : : * 4 : : * This program is free software; you can redistribute it and/or 5 : : * modify it under the terms of the GNU General Public License as 6 : : * published by the Free Software Foundation version 2. 7 : : * 8 : : * This program is distributed "as is" WITHOUT ANY WARRANTY of any 9 : : * kind, whether express or implied; without even the implied warranty 10 : : * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 : : * GNU General Public License for more details. 12 : : */ 13 : : /* 14 : : * DESCRIPTION: The Broadcom iProc RNG200 Driver 15 : : */ 16 : : 17 : : #include <linux/hw_random.h> 18 : : #include <linux/init.h> 19 : : #include <linux/io.h> 20 : : #include <linux/kernel.h> 21 : : #include <linux/module.h> 22 : : #include <linux/of_address.h> 23 : : #include <linux/of_platform.h> 24 : : #include <linux/platform_device.h> 25 : : #include <linux/delay.h> 26 : : 27 : : /* Registers */ 28 : : #define RNG_CTRL_OFFSET 0x00 29 : : #define RNG_CTRL_RNG_RBGEN_MASK 0x00001FFF 30 : : #define RNG_CTRL_RNG_RBGEN_ENABLE 0x00000001 31 : : #define RNG_CTRL_RNG_RBGEN_DISABLE 0x00000000 32 : : #define RNG_CTRL_RNG_DIV_CTRL_SHIFT 13 33 : : 34 : : #define RNG_SOFT_RESET_OFFSET 0x04 35 : : #define RNG_SOFT_RESET 0x00000001 36 : : 37 : : #define RBG_SOFT_RESET_OFFSET 0x08 38 : : #define RBG_SOFT_RESET 0x00000001 39 : : 40 : : #define RNG_TOTAL_BIT_COUNT_OFFSET 0x0C 41 : : 42 : : #define RNG_TOTAL_BIT_COUNT_THRESHOLD_OFFSET 0x10 43 : : 44 : : #define RNG_INT_STATUS_OFFSET 0x18 45 : : #define RNG_INT_STATUS_MASTER_FAIL_LOCKOUT_IRQ_MASK 0x80000000 46 : : #define RNG_INT_STATUS_STARTUP_TRANSITIONS_MET_IRQ_MASK 0x00020000 47 : : #define RNG_INT_STATUS_NIST_FAIL_IRQ_MASK 0x00000020 48 : : #define RNG_INT_STATUS_TOTAL_BITS_COUNT_IRQ_MASK 0x00000001 49 : : 50 : : #define RNG_INT_ENABLE_OFFSET 0x1C 51 : : 52 : : #define RNG_FIFO_DATA_OFFSET 0x20 53 : : 54 : : #define RNG_FIFO_COUNT_OFFSET 0x24 55 : : #define RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK 0x000000FF 56 : : #define RNG_FIFO_COUNT_RNG_FIFO_THRESHOLD_SHIFT 8 57 : : 58 : : struct iproc_rng200_dev { 59 : : struct hwrng rng; 60 : : void __iomem *base; 61 : : }; 62 : : 63 : : #define to_rng_priv(rng) container_of(rng, struct iproc_rng200_dev, rng) 64 : : 65 : 0 : static void iproc_rng200_restart(void __iomem *rng_base) 66 : : { 67 : : uint32_t val; 68 : : 69 : : /* Disable RBG */ 70 : : val = ioread32(rng_base + RNG_CTRL_OFFSET); 71 : 0 : val &= ~RNG_CTRL_RNG_RBGEN_MASK; 72 : : val |= RNG_CTRL_RNG_RBGEN_DISABLE; 73 : : iowrite32(val, rng_base + RNG_CTRL_OFFSET); 74 : : 75 : : /* Clear all interrupt status */ 76 : 0 : iowrite32(0xFFFFFFFFUL, rng_base + RNG_INT_STATUS_OFFSET); 77 : : 78 : : /* Reset RNG and RBG */ 79 : 0 : val = ioread32(rng_base + RBG_SOFT_RESET_OFFSET); 80 : 0 : val |= RBG_SOFT_RESET; 81 : : iowrite32(val, rng_base + RBG_SOFT_RESET_OFFSET); 82 : : 83 : 0 : val = ioread32(rng_base + RNG_SOFT_RESET_OFFSET); 84 : 0 : val |= RNG_SOFT_RESET; 85 : : iowrite32(val, rng_base + RNG_SOFT_RESET_OFFSET); 86 : : 87 : : val = ioread32(rng_base + RNG_SOFT_RESET_OFFSET); 88 : 0 : val &= ~RNG_SOFT_RESET; 89 : : iowrite32(val, rng_base + RNG_SOFT_RESET_OFFSET); 90 : : 91 : : val = ioread32(rng_base + RBG_SOFT_RESET_OFFSET); 92 : 0 : val &= ~RBG_SOFT_RESET; 93 : : iowrite32(val, rng_base + RBG_SOFT_RESET_OFFSET); 94 : : 95 : : /* Enable RBG */ 96 : : val = ioread32(rng_base + RNG_CTRL_OFFSET); 97 : 0 : val &= ~RNG_CTRL_RNG_RBGEN_MASK; 98 : 0 : val |= RNG_CTRL_RNG_RBGEN_ENABLE; 99 : : iowrite32(val, rng_base + RNG_CTRL_OFFSET); 100 : 0 : } 101 : : 102 : 0 : static int iproc_rng200_read(struct hwrng *rng, void *buf, size_t max, 103 : : bool wait) 104 : : { 105 : : struct iproc_rng200_dev *priv = to_rng_priv(rng); 106 : : uint32_t num_remaining = max; 107 : : uint32_t status; 108 : : 109 : : #define MAX_RESETS_PER_READ 1 110 : : uint32_t num_resets = 0; 111 : : 112 : : #define MAX_IDLE_TIME (1 * HZ) 113 : 0 : unsigned long idle_endtime = jiffies + MAX_IDLE_TIME; 114 : : 115 : 0 : while ((num_remaining > 0) && time_before(jiffies, idle_endtime)) { 116 : : 117 : : /* Is RNG sane? If not, reset it. */ 118 : 0 : status = ioread32(priv->base + RNG_INT_STATUS_OFFSET); 119 : 0 : if ((status & (RNG_INT_STATUS_MASTER_FAIL_LOCKOUT_IRQ_MASK | 120 : : RNG_INT_STATUS_NIST_FAIL_IRQ_MASK)) != 0) { 121 : : 122 : 0 : if (num_resets >= MAX_RESETS_PER_READ) 123 : 0 : return max - num_remaining; 124 : : 125 : 0 : iproc_rng200_restart(priv->base); 126 : 0 : num_resets++; 127 : : } 128 : : 129 : : /* Are there any random numbers available? */ 130 : 0 : if ((ioread32(priv->base + RNG_FIFO_COUNT_OFFSET) & 131 : : RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK) > 0) { 132 : : 133 : 0 : if (num_remaining >= sizeof(uint32_t)) { 134 : : /* Buffer has room to store entire word */ 135 : 0 : *(uint32_t *)buf = ioread32(priv->base + 136 : : RNG_FIFO_DATA_OFFSET); 137 : 0 : buf += sizeof(uint32_t); 138 : 0 : num_remaining -= sizeof(uint32_t); 139 : : } else { 140 : : /* Buffer can only store partial word */ 141 : 0 : uint32_t rnd_number = ioread32(priv->base + 142 : : RNG_FIFO_DATA_OFFSET); 143 : 0 : memcpy(buf, &rnd_number, num_remaining); 144 : 0 : buf += num_remaining; 145 : : num_remaining = 0; 146 : : } 147 : : 148 : : /* Reset the IDLE timeout */ 149 : 0 : idle_endtime = jiffies + MAX_IDLE_TIME; 150 : : } else { 151 : 0 : if (!wait) 152 : : /* Cannot wait, return immediately */ 153 : 0 : return max - num_remaining; 154 : : 155 : : /* Can wait, give others chance to run */ 156 : 0 : usleep_range(min(num_remaining * 10, 500U), 500); 157 : : } 158 : : } 159 : : 160 : 0 : return max - num_remaining; 161 : : } 162 : : 163 : 0 : static int iproc_rng200_init(struct hwrng *rng) 164 : : { 165 : : struct iproc_rng200_dev *priv = to_rng_priv(rng); 166 : : uint32_t val; 167 : : 168 : : /* Setup RNG. */ 169 : 0 : val = ioread32(priv->base + RNG_CTRL_OFFSET); 170 : 0 : val &= ~RNG_CTRL_RNG_RBGEN_MASK; 171 : 0 : val |= RNG_CTRL_RNG_RBGEN_ENABLE; 172 : 0 : iowrite32(val, priv->base + RNG_CTRL_OFFSET); 173 : : 174 : 0 : return 0; 175 : : } 176 : : 177 : 0 : static int bcm2711_rng200_read(struct hwrng *rng, void *buf, size_t max, 178 : : bool wait) 179 : : { 180 : : struct iproc_rng200_dev *priv = to_rng_priv(rng); 181 : 0 : u32 max_words = max / sizeof(u32); 182 : : u32 num_words, count, val; 183 : : 184 : : /* ensure warm up period has elapsed */ 185 : : while (1) { 186 : 0 : val = ioread32(priv->base + RNG_TOTAL_BIT_COUNT_OFFSET); 187 : 0 : if (val > 16) 188 : : break; 189 : 0 : cpu_relax(); 190 : 0 : } 191 : : 192 : : /* ensure fifo is not empty */ 193 : : while (1) { 194 : 0 : num_words = ioread32(priv->base + RNG_FIFO_COUNT_OFFSET) & 195 : : RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK; 196 : 0 : if (num_words) 197 : : break; 198 : 0 : if (!wait) 199 : : return 0; 200 : 0 : cpu_relax(); 201 : 0 : } 202 : : 203 : 0 : if (num_words > max_words) 204 : : num_words = max_words; 205 : : 206 : 0 : for (count = 0; count < num_words; count++) { 207 : 0 : ((u32 *)buf)[count] = ioread32(priv->base + 208 : : RNG_FIFO_DATA_OFFSET); 209 : : } 210 : : 211 : 0 : return num_words * sizeof(u32); 212 : : } 213 : : 214 : 0 : static int bcm2711_rng200_init(struct hwrng *rng) 215 : : { 216 : : struct iproc_rng200_dev *priv = to_rng_priv(rng); 217 : : uint32_t val; 218 : : 219 : 0 : if (ioread32(priv->base + RNG_CTRL_OFFSET) & RNG_CTRL_RNG_RBGEN_MASK) 220 : : return 0; 221 : : 222 : : /* initial numbers generated are "less random" so will be discarded */ 223 : : val = 0x40000; 224 : 0 : iowrite32(val, priv->base + RNG_TOTAL_BIT_COUNT_THRESHOLD_OFFSET); 225 : : /* min fifo count to generate full interrupt */ 226 : : val = 2 << RNG_FIFO_COUNT_RNG_FIFO_THRESHOLD_SHIFT; 227 : 0 : iowrite32(val, priv->base + RNG_FIFO_COUNT_OFFSET); 228 : : /* enable the rng - 1Mhz sample rate */ 229 : : val = (0x3 << RNG_CTRL_RNG_DIV_CTRL_SHIFT) | RNG_CTRL_RNG_RBGEN_MASK; 230 : 0 : iowrite32(val, priv->base + RNG_CTRL_OFFSET); 231 : : 232 : 0 : return 0; 233 : : } 234 : : 235 : 0 : static void iproc_rng200_cleanup(struct hwrng *rng) 236 : : { 237 : : struct iproc_rng200_dev *priv = to_rng_priv(rng); 238 : : uint32_t val; 239 : : 240 : : /* Disable RNG hardware */ 241 : 0 : val = ioread32(priv->base + RNG_CTRL_OFFSET); 242 : 0 : val &= ~RNG_CTRL_RNG_RBGEN_MASK; 243 : : val |= RNG_CTRL_RNG_RBGEN_DISABLE; 244 : 0 : iowrite32(val, priv->base + RNG_CTRL_OFFSET); 245 : 0 : } 246 : : 247 : 0 : static int iproc_rng200_probe(struct platform_device *pdev) 248 : : { 249 : : struct iproc_rng200_dev *priv; 250 : : struct resource *res; 251 : 0 : struct device *dev = &pdev->dev; 252 : : int ret; 253 : : 254 : : priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 255 : 0 : if (!priv) 256 : : return -ENOMEM; 257 : : 258 : : /* Map peripheral */ 259 : 0 : res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 260 : 0 : if (!res) { 261 : 0 : dev_err(dev, "failed to get rng resources\n"); 262 : 0 : return -EINVAL; 263 : : } 264 : : 265 : 0 : priv->base = devm_ioremap_resource(dev, res); 266 : 0 : if (IS_ERR(priv->base)) { 267 : 0 : dev_err(dev, "failed to remap rng regs\n"); 268 : 0 : return PTR_ERR(priv->base); 269 : : } 270 : : 271 : 0 : priv->rng.name = pdev->name; 272 : 0 : priv->rng.cleanup = iproc_rng200_cleanup; 273 : : 274 : 0 : if (of_device_is_compatible(dev->of_node, "brcm,bcm2711-rng200")) { 275 : 0 : priv->rng.init = bcm2711_rng200_init; 276 : 0 : priv->rng.read = bcm2711_rng200_read; 277 : : } else { 278 : 0 : priv->rng.init = iproc_rng200_init; 279 : 0 : priv->rng.read = iproc_rng200_read; 280 : : } 281 : : 282 : : /* Register driver */ 283 : 0 : ret = devm_hwrng_register(dev, &priv->rng); 284 : 0 : if (ret) { 285 : 0 : dev_err(dev, "hwrng registration failed\n"); 286 : 0 : return ret; 287 : : } 288 : : 289 : 0 : dev_info(dev, "hwrng registered\n"); 290 : : 291 : 0 : return 0; 292 : : } 293 : : 294 : : static const struct of_device_id iproc_rng200_of_match[] = { 295 : : { .compatible = "brcm,bcm2711-rng200", }, 296 : : { .compatible = "brcm,bcm7211-rng200", }, 297 : : { .compatible = "brcm,bcm7278-rng200", }, 298 : : { .compatible = "brcm,iproc-rng200", }, 299 : : {}, 300 : : }; 301 : : MODULE_DEVICE_TABLE(of, iproc_rng200_of_match); 302 : : 303 : : static struct platform_driver iproc_rng200_driver = { 304 : : .driver = { 305 : : .name = "iproc-rng200", 306 : : .of_match_table = iproc_rng200_of_match, 307 : : }, 308 : : .probe = iproc_rng200_probe, 309 : : }; 310 : 3 : module_platform_driver(iproc_rng200_driver); 311 : : 312 : : MODULE_AUTHOR("Broadcom"); 313 : : MODULE_DESCRIPTION("iProc RNG200 Random Number Generator driver"); 314 : : MODULE_LICENSE("GPL v2");