root/drivers/crypto/amcc/crypto4xx_trng.c

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

DEFINITIONS

This source file includes following definitions.
  1. ppc4xx_trng_data_present
  2. ppc4xx_trng_data_read
  3. ppc4xx_trng_enable
  4. ppc4xx_trng_probe
  5. ppc4xx_trng_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Generic PowerPC 44x RNG driver
   4  *
   5  * Copyright 2011 IBM Corporation
   6  */
   7 
   8 #include <linux/module.h>
   9 #include <linux/kernel.h>
  10 #include <linux/interrupt.h>
  11 #include <linux/platform_device.h>
  12 #include <linux/hw_random.h>
  13 #include <linux/delay.h>
  14 #include <linux/of_address.h>
  15 #include <linux/of_platform.h>
  16 #include <linux/io.h>
  17 
  18 #include "crypto4xx_core.h"
  19 #include "crypto4xx_trng.h"
  20 #include "crypto4xx_reg_def.h"
  21 
  22 #define PPC4XX_TRNG_CTRL        0x0008
  23 #define PPC4XX_TRNG_CTRL_DALM   0x20
  24 #define PPC4XX_TRNG_STAT        0x0004
  25 #define PPC4XX_TRNG_STAT_B      0x1
  26 #define PPC4XX_TRNG_DATA        0x0000
  27 
  28 static int ppc4xx_trng_data_present(struct hwrng *rng, int wait)
  29 {
  30         struct crypto4xx_device *dev = (void *)rng->priv;
  31         int busy, i, present = 0;
  32 
  33         for (i = 0; i < 20; i++) {
  34                 busy = (in_le32(dev->trng_base + PPC4XX_TRNG_STAT) &
  35                         PPC4XX_TRNG_STAT_B);
  36                 if (!busy || !wait) {
  37                         present = 1;
  38                         break;
  39                 }
  40                 udelay(10);
  41         }
  42         return present;
  43 }
  44 
  45 static int ppc4xx_trng_data_read(struct hwrng *rng, u32 *data)
  46 {
  47         struct crypto4xx_device *dev = (void *)rng->priv;
  48         *data = in_le32(dev->trng_base + PPC4XX_TRNG_DATA);
  49         return 4;
  50 }
  51 
  52 static void ppc4xx_trng_enable(struct crypto4xx_device *dev, bool enable)
  53 {
  54         u32 device_ctrl;
  55 
  56         device_ctrl = readl(dev->ce_base + CRYPTO4XX_DEVICE_CTRL);
  57         if (enable)
  58                 device_ctrl |= PPC4XX_TRNG_EN;
  59         else
  60                 device_ctrl &= ~PPC4XX_TRNG_EN;
  61         writel(device_ctrl, dev->ce_base + CRYPTO4XX_DEVICE_CTRL);
  62 }
  63 
  64 static const struct of_device_id ppc4xx_trng_match[] = {
  65         { .compatible = "ppc4xx-rng", },
  66         { .compatible = "amcc,ppc460ex-rng", },
  67         { .compatible = "amcc,ppc440epx-rng", },
  68         {},
  69 };
  70 
  71 void ppc4xx_trng_probe(struct crypto4xx_core_device *core_dev)
  72 {
  73         struct crypto4xx_device *dev = core_dev->dev;
  74         struct device_node *trng = NULL;
  75         struct hwrng *rng = NULL;
  76         int err;
  77 
  78         /* Find the TRNG device node and map it */
  79         trng = of_find_matching_node(NULL, ppc4xx_trng_match);
  80         if (!trng || !of_device_is_available(trng)) {
  81                 of_node_put(trng);
  82                 return;
  83         }
  84 
  85         dev->trng_base = of_iomap(trng, 0);
  86         of_node_put(trng);
  87         if (!dev->trng_base)
  88                 goto err_out;
  89 
  90         rng = kzalloc(sizeof(*rng), GFP_KERNEL);
  91         if (!rng)
  92                 goto err_out;
  93 
  94         rng->name = KBUILD_MODNAME;
  95         rng->data_present = ppc4xx_trng_data_present;
  96         rng->data_read = ppc4xx_trng_data_read;
  97         rng->priv = (unsigned long) dev;
  98         core_dev->trng = rng;
  99         ppc4xx_trng_enable(dev, true);
 100         out_le32(dev->trng_base + PPC4XX_TRNG_CTRL, PPC4XX_TRNG_CTRL_DALM);
 101         err = devm_hwrng_register(core_dev->device, core_dev->trng);
 102         if (err) {
 103                 ppc4xx_trng_enable(dev, false);
 104                 dev_err(core_dev->device, "failed to register hwrng (%d).\n",
 105                         err);
 106                 goto err_out;
 107         }
 108         return;
 109 
 110 err_out:
 111         iounmap(dev->trng_base);
 112         kfree(rng);
 113         dev->trng_base = NULL;
 114         core_dev->trng = NULL;
 115 }
 116 
 117 void ppc4xx_trng_remove(struct crypto4xx_core_device *core_dev)
 118 {
 119         if (core_dev && core_dev->trng) {
 120                 struct crypto4xx_device *dev = core_dev->dev;
 121 
 122                 devm_hwrng_unregister(core_dev->device, core_dev->trng);
 123                 ppc4xx_trng_enable(dev, false);
 124                 iounmap(dev->trng_base);
 125                 kfree(core_dev->trng);
 126         }
 127 }
 128 
 129 MODULE_ALIAS("ppc4xx_rng");

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