199 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * RNG driver for Freescale RNGA4 *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 0x0024#define RNGA_STATUS 0x0425#define RNGA_ENTROPY 0x0826#define RNGA_OUTPUT_FIFO 0x0c27#define RNGA_MODE 0x1028#define RNGA_VERIFICATION_CONTROL 0x1429#define RNGA_OSC_CONTROL_COUNTER 0x1830#define RNGA_OSC1_COUNTER 0x1c31#define RNGA_OSC2_COUNTER 0x2032#define RNGA_OSC_COUNTER_STATUS 0x2433 34/* RNGA Registers Range */35#define RNG_ADDR_RANGE 0x2836 37/* RNGA Control Register */38#define RNGA_CONTROL_SLEEP 0x0000001039#define RNGA_CONTROL_CLEAR_INT 0x0000000840#define RNGA_CONTROL_MASK_INTS 0x0000000441#define RNGA_CONTROL_HIGH_ASSURANCE 0x0000000242#define RNGA_CONTROL_GO 0x0000000143 44#define RNGA_STATUS_LEVEL_MASK 0x0000ff0045 46/* RNGA Status Register */47#define RNGA_STATUS_OSC_DEAD 0x8000000048#define RNGA_STATUS_SLEEP 0x0000001049#define RNGA_STATUS_ERROR_INT 0x0000000850#define RNGA_STATUS_FIFO_UNDERFLOW 0x0000000451#define RNGA_STATUS_LAST_READ_STATUS 0x0000000252#define RNGA_STATUS_SECURITY_VIOLATION 0x0000000153 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 } else97 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 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_enabled(&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 mxc_rng->mem = devm_platform_ioremap_resource(pdev, 0);157 if (IS_ERR(mxc_rng->mem)) {158 err = PTR_ERR(mxc_rng->mem);159 return err;160 }161 162 err = hwrng_register(&mxc_rng->rng);163 if (err) {164 dev_err(&pdev->dev, "MXC RNGA registering failed (%d)\n", err);165 return err;166 }167 168 return 0;169}170 171static void mxc_rnga_remove(struct platform_device *pdev)172{173 struct mxc_rng *mxc_rng = platform_get_drvdata(pdev);174 175 hwrng_unregister(&mxc_rng->rng);176}177 178static const struct of_device_id mxc_rnga_of_match[] = {179 { .compatible = "fsl,imx21-rnga", },180 { .compatible = "fsl,imx31-rnga", },181 { /* sentinel */ },182};183MODULE_DEVICE_TABLE(of, mxc_rnga_of_match);184 185static struct platform_driver mxc_rnga_driver = {186 .driver = {187 .name = "mxc_rnga",188 .of_match_table = mxc_rnga_of_match,189 },190 .probe = mxc_rnga_probe,191 .remove_new = mxc_rnga_remove,192};193 194module_platform_driver(mxc_rnga_driver);195 196MODULE_AUTHOR("Freescale Semiconductor, Inc.");197MODULE_DESCRIPTION("H/W RNGA driver for i.MX");198MODULE_LICENSE("GPL");199