brintos

brintos / linux-shallow public Read only

0
0
Text · 5.0 KiB · f01eb95 Raw
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