Commit 8c4196a2fd7c31acd6d02d9921f7896b8f160c92

Authored by Lubomir Rintel
Committed by Herbert Xu
1 parent 96aef9a8ba

hwrng: bcm2835 - Add Broadcom BCM2835 RNG driver

This adds a driver for random number generator present on Broadcom BCM2835 SoC,
used in Raspberry Pi and Roku 2 devices.

Signed-off-by: Dom Cobley <popcornmix@gmail.com>
Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
Tested-by: Stephen Warren <swarren@wwwdotorg.org>
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: Stephen Warren <swarren@wwwdotorg.org>
Cc: Matt Mackall <mpm@selenic.com>
Cc: linux-rpi-kernel@lists.infradead.org
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

Showing 4 changed files with 139 additions and 0 deletions Side-by-side Diff

Documentation/devicetree/bindings/rng/brcm,bcm2835.txt
  1 +BCM2835 Random number generator
  2 +
  3 +Required properties:
  4 +
  5 +- compatible : should be "brcm,bcm2835-rng"
  6 +- reg : Specifies base physical address and size of the registers.
  7 +
  8 +Example:
  9 +
  10 +rng {
  11 + compatible = "brcm,bcm2835-rng";
  12 + reg = <0x7e104000 0x10>;
  13 +};
drivers/char/hw_random/Kconfig
... ... @@ -86,6 +86,18 @@
86 86  
87 87 If unusure, say Y.
88 88  
  89 +config HW_RANDOM_BCM2835
  90 + tristate "Broadcom BCM2835 Random Number Generator support"
  91 + depends on HW_RANDOM && ARCH_BCM2835
  92 + default HW_RANDOM
  93 + ---help---
  94 + This driver provides kernel-side support for the Random Number
  95 + Generator hardware found on the Broadcom BCM2835 SoCs.
  96 +
  97 + To compile this driver as a module, choose M here: the
  98 + module will be called bcm2835-rng
  99 +
  100 + If unsure, say Y.
89 101  
90 102 config HW_RANDOM_GEODE
91 103 tristate "AMD Geode HW Random Number Generator support"
drivers/char/hw_random/Makefile
... ... @@ -26,4 +26,5 @@
26 26 obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o
27 27 obj-$(CONFIG_HW_RANDOM_EXYNOS) += exynos-rng.o
28 28 obj-$(CONFIG_HW_RANDOM_TPM) += tpm-rng.o
  29 +obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o
drivers/char/hw_random/bcm2835-rng.c
  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/init.h>
  12 +#include <linux/io.h>
  13 +#include <linux/kernel.h>
  14 +#include <linux/module.h>
  15 +#include <linux/of_address.h>
  16 +#include <linux/of_platform.h>
  17 +#include <linux/platform_device.h>
  18 +#include <linux/printk.h>
  19 +
  20 +#define RNG_CTRL 0x0
  21 +#define RNG_STATUS 0x4
  22 +#define RNG_DATA 0x8
  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 +static int bcm2835_rng_read(struct hwrng *rng, void *buf, size_t max,
  31 + bool wait)
  32 +{
  33 + void __iomem *rng_base = (void __iomem *)rng->priv;
  34 +
  35 + while ((__raw_readl(rng_base + RNG_STATUS) >> 24) == 0) {
  36 + if (!wait)
  37 + return 0;
  38 + cpu_relax();
  39 + }
  40 +
  41 + *(u32 *)buf = __raw_readl(rng_base + RNG_DATA);
  42 + return sizeof(u32);
  43 +}
  44 +
  45 +static struct hwrng bcm2835_rng_ops = {
  46 + .name = "bcm2835",
  47 + .read = bcm2835_rng_read,
  48 +};
  49 +
  50 +static int bcm2835_rng_probe(struct platform_device *pdev)
  51 +{
  52 + struct device *dev = &pdev->dev;
  53 + struct device_node *np = dev->of_node;
  54 + void __iomem *rng_base;
  55 + int err;
  56 +
  57 + /* map peripheral */
  58 + rng_base = of_iomap(np, 0);
  59 + if (!rng_base) {
  60 + dev_err(dev, "failed to remap rng regs");
  61 + return -ENODEV;
  62 + }
  63 + bcm2835_rng_ops.priv = (unsigned long)rng_base;
  64 +
  65 + /* register driver */
  66 + err = hwrng_register(&bcm2835_rng_ops);
  67 + if (err) {
  68 + dev_err(dev, "hwrng registration failed\n");
  69 + iounmap(rng_base);
  70 + } else {
  71 + dev_info(dev, "hwrng registered\n");
  72 +
  73 + /* set warm-up count & enable */
  74 + __raw_writel(RNG_WARMUP_COUNT, rng_base + RNG_STATUS);
  75 + __raw_writel(RNG_RBGEN, rng_base + RNG_CTRL);
  76 + }
  77 + return err;
  78 +}
  79 +
  80 +static int bcm2835_rng_remove(struct platform_device *pdev)
  81 +{
  82 + void __iomem *rng_base = (void __iomem *)bcm2835_rng_ops.priv;
  83 +
  84 + /* disable rng hardware */
  85 + __raw_writel(0, rng_base + RNG_CTRL);
  86 +
  87 + /* unregister driver */
  88 + hwrng_unregister(&bcm2835_rng_ops);
  89 + iounmap(rng_base);
  90 +
  91 + return 0;
  92 +}
  93 +
  94 +static const struct of_device_id bcm2835_rng_of_match[] = {
  95 + { .compatible = "brcm,bcm2835-rng", },
  96 + {},
  97 +};
  98 +MODULE_DEVICE_TABLE(of, bcm2835_rng_of_match);
  99 +
  100 +static struct platform_driver bcm2835_rng_driver = {
  101 + .driver = {
  102 + .name = "bcm2835-rng",
  103 + .owner = THIS_MODULE,
  104 + .of_match_table = bcm2835_rng_of_match,
  105 + },
  106 + .probe = bcm2835_rng_probe,
  107 + .remove = bcm2835_rng_remove,
  108 +};
  109 +module_platform_driver(bcm2835_rng_driver);
  110 +
  111 +MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>");
  112 +MODULE_DESCRIPTION("BCM2835 Random Number Generator (RNG) driver");
  113 +MODULE_LICENSE("GPLv2");