cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

st-rng.c (3445B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * ST Random Number Generator Driver ST's Platforms
      4 *
      5 * Author: Pankaj Dev: <pankaj.dev@st.com>
      6 *         Lee Jones <lee.jones@linaro.org>
      7 *
      8 * Copyright (C) 2015 STMicroelectronics (R&D) Limited
      9 */
     10
     11#include <linux/clk.h>
     12#include <linux/delay.h>
     13#include <linux/hw_random.h>
     14#include <linux/io.h>
     15#include <linux/kernel.h>
     16#include <linux/module.h>
     17#include <linux/of.h>
     18#include <linux/platform_device.h>
     19#include <linux/slab.h>
     20
     21/* Registers */
     22#define ST_RNG_STATUS_REG		0x20
     23#define ST_RNG_DATA_REG			0x24
     24
     25/* Registers fields */
     26#define ST_RNG_STATUS_BAD_SEQUENCE	BIT(0)
     27#define ST_RNG_STATUS_BAD_ALTERNANCE	BIT(1)
     28#define ST_RNG_STATUS_FIFO_FULL		BIT(5)
     29
     30#define ST_RNG_SAMPLE_SIZE		2 /* 2 Byte (16bit) samples */
     31#define ST_RNG_FIFO_DEPTH		4
     32#define ST_RNG_FIFO_SIZE		(ST_RNG_FIFO_DEPTH * ST_RNG_SAMPLE_SIZE)
     33
     34/*
     35 * Samples are documented to be available every 0.667us, so in theory
     36 * the 4 sample deep FIFO should take 2.668us to fill.  However, during
     37 * thorough testing, it became apparent that filling the FIFO actually
     38 * takes closer to 12us.  We then multiply by 2 in order to account for
     39 * the lack of udelay()'s reliability, suggested by Russell King.
     40 */
     41#define ST_RNG_FILL_FIFO_TIMEOUT	(12 * 2)
     42
     43struct st_rng_data {
     44	void __iomem	*base;
     45	struct clk	*clk;
     46	struct hwrng	ops;
     47};
     48
     49static int st_rng_read(struct hwrng *rng, void *data, size_t max, bool wait)
     50{
     51	struct st_rng_data *ddata = (struct st_rng_data *)rng->priv;
     52	u32 status;
     53	int i;
     54
     55	/* Wait until FIFO is full - max 4uS*/
     56	for (i = 0; i < ST_RNG_FILL_FIFO_TIMEOUT; i++) {
     57		status = readl_relaxed(ddata->base + ST_RNG_STATUS_REG);
     58		if (status & ST_RNG_STATUS_FIFO_FULL)
     59			break;
     60		udelay(1);
     61	}
     62
     63	if (i == ST_RNG_FILL_FIFO_TIMEOUT)
     64		return 0;
     65
     66	for (i = 0; i < ST_RNG_FIFO_SIZE && i < max; i += 2)
     67		*(u16 *)(data + i) =
     68			readl_relaxed(ddata->base + ST_RNG_DATA_REG);
     69
     70	return i;	/* No of bytes read */
     71}
     72
     73static int st_rng_probe(struct platform_device *pdev)
     74{
     75	struct st_rng_data *ddata;
     76	struct clk *clk;
     77	void __iomem *base;
     78	int ret;
     79
     80	ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
     81	if (!ddata)
     82		return -ENOMEM;
     83
     84	base = devm_platform_ioremap_resource(pdev, 0);
     85	if (IS_ERR(base))
     86		return PTR_ERR(base);
     87
     88	clk = devm_clk_get(&pdev->dev, NULL);
     89	if (IS_ERR(clk))
     90		return PTR_ERR(clk);
     91
     92	ret = clk_prepare_enable(clk);
     93	if (ret)
     94		return ret;
     95
     96	ddata->ops.priv	= (unsigned long)ddata;
     97	ddata->ops.read	= st_rng_read;
     98	ddata->ops.name	= pdev->name;
     99	ddata->base	= base;
    100	ddata->clk	= clk;
    101
    102	dev_set_drvdata(&pdev->dev, ddata);
    103
    104	ret = devm_hwrng_register(&pdev->dev, &ddata->ops);
    105	if (ret) {
    106		dev_err(&pdev->dev, "Failed to register HW RNG\n");
    107		clk_disable_unprepare(clk);
    108		return ret;
    109	}
    110
    111	dev_info(&pdev->dev, "Successfully registered HW RNG\n");
    112
    113	return 0;
    114}
    115
    116static int st_rng_remove(struct platform_device *pdev)
    117{
    118	struct st_rng_data *ddata = dev_get_drvdata(&pdev->dev);
    119
    120	clk_disable_unprepare(ddata->clk);
    121
    122	return 0;
    123}
    124
    125static const struct of_device_id st_rng_match[] __maybe_unused = {
    126	{ .compatible = "st,rng" },
    127	{},
    128};
    129MODULE_DEVICE_TABLE(of, st_rng_match);
    130
    131static struct platform_driver st_rng_driver = {
    132	.driver = {
    133		.name = "st-hwrandom",
    134		.of_match_table = of_match_ptr(st_rng_match),
    135	},
    136	.probe = st_rng_probe,
    137	.remove = st_rng_remove
    138};
    139
    140module_platform_driver(st_rng_driver);
    141
    142MODULE_AUTHOR("Pankaj Dev <pankaj.dev@st.com>");
    143MODULE_LICENSE("GPL v2");