linux/drivers/char/hw_random/mxc-rnga.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * RNG driver for Freescale RNGA
   4 *
   5 * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
   6 * Author: Alan Carvalho de Assis <acassis@gmail.com>
   7 */
   8
   9/*
  10 *
  11 * This driver is based on other RNG drivers.
  12 */
  13
  14#include <linux/clk.h>
  15#include <linux/delay.h>
  16#include <linux/hw_random.h>
  17#include <linux/io.h>
  18#include <linux/module.h>
  19#include <linux/of.h>
  20#include <linux/platform_device.h>
  21
  22/* RNGA Registers */
  23#define RNGA_CONTROL                    0x00
  24#define RNGA_STATUS                     0x04
  25#define RNGA_ENTROPY                    0x08
  26#define RNGA_OUTPUT_FIFO                0x0c
  27#define RNGA_MODE                       0x10
  28#define RNGA_VERIFICATION_CONTROL       0x14
  29#define RNGA_OSC_CONTROL_COUNTER        0x18
  30#define RNGA_OSC1_COUNTER               0x1c
  31#define RNGA_OSC2_COUNTER               0x20
  32#define RNGA_OSC_COUNTER_STATUS         0x24
  33
  34/* RNGA Registers Range */
  35#define RNG_ADDR_RANGE                  0x28
  36
  37/* RNGA Control Register */
  38#define RNGA_CONTROL_SLEEP              0x00000010
  39#define RNGA_CONTROL_CLEAR_INT          0x00000008
  40#define RNGA_CONTROL_MASK_INTS          0x00000004
  41#define RNGA_CONTROL_HIGH_ASSURANCE     0x00000002
  42#define RNGA_CONTROL_GO                 0x00000001
  43
  44#define RNGA_STATUS_LEVEL_MASK          0x0000ff00
  45
  46/* RNGA Status Register */
  47#define RNGA_STATUS_OSC_DEAD            0x80000000
  48#define RNGA_STATUS_SLEEP               0x00000010
  49#define RNGA_STATUS_ERROR_INT           0x00000008
  50#define RNGA_STATUS_FIFO_UNDERFLOW      0x00000004
  51#define RNGA_STATUS_LAST_READ_STATUS    0x00000002
  52#define RNGA_STATUS_SECURITY_VIOLATION  0x00000001
  53
  54struct mxc_rng {
  55        struct device *dev;
  56        struct hwrng rng;
  57        void __iomem *mem;
  58        struct clk *clk;
  59};
  60
  61static int mxc_rnga_data_present(struct hwrng *rng, int wait)
  62{
  63        int i;
  64        struct mxc_rng *mxc_rng = container_of(rng, struct mxc_rng, rng);
  65
  66        for (i = 0; i < 20; i++) {
  67                /* how many random numbers are in FIFO? [0-16] */
  68                int level = (__raw_readl(mxc_rng->mem + RNGA_STATUS) &
  69                                RNGA_STATUS_LEVEL_MASK) >> 8;
  70                if (level || !wait)
  71                        return !!level;
  72                udelay(10);
  73        }
  74        return 0;
  75}
  76
  77static int mxc_rnga_data_read(struct hwrng *rng, u32 * data)
  78{
  79        int err;
  80        u32 ctrl;
  81        struct mxc_rng *mxc_rng = container_of(rng, struct mxc_rng, rng);
  82
  83        /* retrieve a random number from FIFO */
  84        *data = __raw_readl(mxc_rng->mem + RNGA_OUTPUT_FIFO);
  85
  86        /* some error while reading this random number? */
  87        err = __raw_readl(mxc_rng->mem + RNGA_STATUS) & RNGA_STATUS_ERROR_INT;
  88
  89        /* if error: clear error interrupt, but doesn't return random number */
  90        if (err) {
  91                dev_dbg(mxc_rng->dev, "Error while reading random number!\n");
  92                ctrl = __raw_readl(mxc_rng->mem + RNGA_CONTROL);
  93                __raw_writel(ctrl | RNGA_CONTROL_CLEAR_INT,
  94                                        mxc_rng->mem + RNGA_CONTROL);
  95                return 0;
  96        } else
  97                return 4;
  98}
  99
 100static int mxc_rnga_init(struct hwrng *rng)
 101{
 102        u32 ctrl, osc;
 103        struct mxc_rng *mxc_rng = container_of(rng, struct mxc_rng, rng);
 104
 105        /* wake up */
 106        ctrl = __raw_readl(mxc_rng->mem + RNGA_CONTROL);
 107        __raw_writel(ctrl & ~RNGA_CONTROL_SLEEP, mxc_rng->mem + RNGA_CONTROL);
 108
 109        /* verify if oscillator is working */
 110        osc = __raw_readl(mxc_rng->mem + RNGA_STATUS);
 111        if (osc & RNGA_STATUS_OSC_DEAD) {
 112                dev_err(mxc_rng->dev, "RNGA Oscillator is dead!\n");
 113                return -ENODEV;
 114        }
 115
 116        /* go running */
 117        ctrl = __raw_readl(mxc_rng->mem + RNGA_CONTROL);
 118        __raw_writel(ctrl | RNGA_CONTROL_GO, mxc_rng->mem + RNGA_CONTROL);
 119
 120        return 0;
 121}
 122
 123static void mxc_rnga_cleanup(struct hwrng *rng)
 124{
 125        u32 ctrl;
 126        struct mxc_rng *mxc_rng = container_of(rng, struct mxc_rng, rng);
 127
 128        ctrl = __raw_readl(mxc_rng->mem + RNGA_CONTROL);
 129
 130        /* stop rnga */
 131        __raw_writel(ctrl & ~RNGA_CONTROL_GO, mxc_rng->mem + RNGA_CONTROL);
 132}
 133
 134static int __init mxc_rnga_probe(struct platform_device *pdev)
 135{
 136        int err;
 137        struct mxc_rng *mxc_rng;
 138
 139        mxc_rng = devm_kzalloc(&pdev->dev, sizeof(*mxc_rng), GFP_KERNEL);
 140        if (!mxc_rng)
 141                return -ENOMEM;
 142
 143        mxc_rng->dev = &pdev->dev;
 144        mxc_rng->rng.name = "mxc-rnga";
 145        mxc_rng->rng.init = mxc_rnga_init;
 146        mxc_rng->rng.cleanup = mxc_rnga_cleanup;
 147        mxc_rng->rng.data_present = mxc_rnga_data_present;
 148        mxc_rng->rng.data_read = mxc_rnga_data_read;
 149
 150        mxc_rng->clk = devm_clk_get(&pdev->dev, NULL);
 151        if (IS_ERR(mxc_rng->clk)) {
 152                dev_err(&pdev->dev, "Could not get rng_clk!\n");
 153                return PTR_ERR(mxc_rng->clk);
 154        }
 155
 156        err = clk_prepare_enable(mxc_rng->clk);
 157        if (err)
 158                return err;
 159
 160        mxc_rng->mem = devm_platform_ioremap_resource(pdev, 0);
 161        if (IS_ERR(mxc_rng->mem)) {
 162                err = PTR_ERR(mxc_rng->mem);
 163                goto err_ioremap;
 164        }
 165
 166        err = hwrng_register(&mxc_rng->rng);
 167        if (err) {
 168                dev_err(&pdev->dev, "MXC RNGA registering failed (%d)\n", err);
 169                goto err_ioremap;
 170        }
 171
 172        return 0;
 173
 174err_ioremap:
 175        clk_disable_unprepare(mxc_rng->clk);
 176        return err;
 177}
 178
 179static int __exit mxc_rnga_remove(struct platform_device *pdev)
 180{
 181        struct mxc_rng *mxc_rng = platform_get_drvdata(pdev);
 182
 183        hwrng_unregister(&mxc_rng->rng);
 184
 185        clk_disable_unprepare(mxc_rng->clk);
 186
 187        return 0;
 188}
 189
 190static const struct of_device_id mxc_rnga_of_match[] = {
 191        { .compatible = "fsl,imx21-rnga", },
 192        { .compatible = "fsl,imx31-rnga", },
 193        { /* sentinel */ },
 194};
 195MODULE_DEVICE_TABLE(of, mxc_rnga_of_match);
 196
 197static struct platform_driver mxc_rnga_driver = {
 198        .driver = {
 199                .name = "mxc_rnga",
 200                .of_match_table = mxc_rnga_of_match,
 201        },
 202        .remove = __exit_p(mxc_rnga_remove),
 203};
 204
 205module_platform_driver_probe(mxc_rnga_driver, mxc_rnga_probe);
 206
 207MODULE_AUTHOR("Freescale Semiconductor, Inc.");
 208MODULE_DESCRIPTION("H/W RNGA driver for i.MX");
 209MODULE_LICENSE("GPL");
 210