root/drivers/char/hw_random/tx4939-rng.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rng_io_start
  2. rng_io_end
  3. read_rng
  4. write_rng
  5. tx4939_rng_data_present
  6. tx4939_rng_data_read
  7. tx4939_rng_probe

   1 /*
   2  * RNG driver for TX4939 Random Number Generators (RNG)
   3  *
   4  * Copyright (C) 2009 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
   5  *
   6  * This file is subject to the terms and conditions of the GNU General Public
   7  * License.  See the file "COPYING" in the main directory of this archive
   8  * for more details.
   9  */
  10 #include <linux/err.h>
  11 #include <linux/module.h>
  12 #include <linux/kernel.h>
  13 #include <linux/init.h>
  14 #include <linux/delay.h>
  15 #include <linux/io.h>
  16 #include <linux/platform_device.h>
  17 #include <linux/hw_random.h>
  18 #include <linux/gfp.h>
  19 
  20 #define TX4939_RNG_RCSR         0x00000000
  21 #define TX4939_RNG_ROR(n)       (0x00000018 + (n) * 8)
  22 
  23 #define TX4939_RNG_RCSR_INTE    0x00000008
  24 #define TX4939_RNG_RCSR_RST     0x00000004
  25 #define TX4939_RNG_RCSR_FIN     0x00000002
  26 #define TX4939_RNG_RCSR_ST      0x00000001
  27 
  28 struct tx4939_rng {
  29         struct hwrng rng;
  30         void __iomem *base;
  31         u64 databuf[3];
  32         unsigned int data_avail;
  33 };
  34 
  35 static void rng_io_start(void)
  36 {
  37 #ifndef CONFIG_64BIT
  38         /*
  39          * readq is reading a 64-bit register using a 64-bit load.  On
  40          * a 32-bit kernel however interrupts or any other processor
  41          * exception would clobber the upper 32-bit of the processor
  42          * register so interrupts need to be disabled.
  43          */
  44         local_irq_disable();
  45 #endif
  46 }
  47 
  48 static void rng_io_end(void)
  49 {
  50 #ifndef CONFIG_64BIT
  51         local_irq_enable();
  52 #endif
  53 }
  54 
  55 static u64 read_rng(void __iomem *base, unsigned int offset)
  56 {
  57         return ____raw_readq(base + offset);
  58 }
  59 
  60 static void write_rng(u64 val, void __iomem *base, unsigned int offset)
  61 {
  62         return ____raw_writeq(val, base + offset);
  63 }
  64 
  65 static int tx4939_rng_data_present(struct hwrng *rng, int wait)
  66 {
  67         struct tx4939_rng *rngdev = container_of(rng, struct tx4939_rng, rng);
  68         int i;
  69 
  70         if (rngdev->data_avail)
  71                 return rngdev->data_avail;
  72         for (i = 0; i < 20; i++) {
  73                 rng_io_start();
  74                 if (!(read_rng(rngdev->base, TX4939_RNG_RCSR)
  75                       & TX4939_RNG_RCSR_ST)) {
  76                         rngdev->databuf[0] =
  77                                 read_rng(rngdev->base, TX4939_RNG_ROR(0));
  78                         rngdev->databuf[1] =
  79                                 read_rng(rngdev->base, TX4939_RNG_ROR(1));
  80                         rngdev->databuf[2] =
  81                                 read_rng(rngdev->base, TX4939_RNG_ROR(2));
  82                         rngdev->data_avail =
  83                                 sizeof(rngdev->databuf) / sizeof(u32);
  84                         /* Start RNG */
  85                         write_rng(TX4939_RNG_RCSR_ST,
  86                                   rngdev->base, TX4939_RNG_RCSR);
  87                         wait = 0;
  88                 }
  89                 rng_io_end();
  90                 if (!wait)
  91                         break;
  92                 /* 90 bus clock cycles by default for generation */
  93                 ndelay(90 * 5);
  94         }
  95         return rngdev->data_avail;
  96 }
  97 
  98 static int tx4939_rng_data_read(struct hwrng *rng, u32 *buffer)
  99 {
 100         struct tx4939_rng *rngdev = container_of(rng, struct tx4939_rng, rng);
 101 
 102         rngdev->data_avail--;
 103         *buffer = *((u32 *)&rngdev->databuf + rngdev->data_avail);
 104         return sizeof(u32);
 105 }
 106 
 107 static int __init tx4939_rng_probe(struct platform_device *dev)
 108 {
 109         struct tx4939_rng *rngdev;
 110         struct resource *r;
 111         int i;
 112 
 113         rngdev = devm_kzalloc(&dev->dev, sizeof(*rngdev), GFP_KERNEL);
 114         if (!rngdev)
 115                 return -ENOMEM;
 116         r = platform_get_resource(dev, IORESOURCE_MEM, 0);
 117         rngdev->base = devm_ioremap_resource(&dev->dev, r);
 118         if (IS_ERR(rngdev->base))
 119                 return PTR_ERR(rngdev->base);
 120 
 121         rngdev->rng.name = dev_name(&dev->dev);
 122         rngdev->rng.data_present = tx4939_rng_data_present;
 123         rngdev->rng.data_read = tx4939_rng_data_read;
 124 
 125         rng_io_start();
 126         /* Reset RNG */
 127         write_rng(TX4939_RNG_RCSR_RST, rngdev->base, TX4939_RNG_RCSR);
 128         write_rng(0, rngdev->base, TX4939_RNG_RCSR);
 129         /* Start RNG */
 130         write_rng(TX4939_RNG_RCSR_ST, rngdev->base, TX4939_RNG_RCSR);
 131         rng_io_end();
 132         /*
 133          * Drop first two results.  From the datasheet:
 134          * The quality of the random numbers generated immediately
 135          * after reset can be insufficient.  Therefore, do not use
 136          * random numbers obtained from the first and second
 137          * generations; use the ones from the third or subsequent
 138          * generation.
 139          */
 140         for (i = 0; i < 2; i++) {
 141                 rngdev->data_avail = 0;
 142                 if (!tx4939_rng_data_present(&rngdev->rng, 1))
 143                         return -EIO;
 144         }
 145 
 146         platform_set_drvdata(dev, rngdev);
 147         return devm_hwrng_register(&dev->dev, &rngdev->rng);
 148 }
 149 
 150 static struct platform_driver tx4939_rng_driver = {
 151         .driver         = {
 152                 .name   = "tx4939-rng",
 153         },
 154 };
 155 
 156 module_platform_driver_probe(tx4939_rng_driver, tx4939_rng_probe);
 157 
 158 MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver for TX4939");
 159 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */