brintos

brintos / linux-shallow public Read only

0
0
Text · 2.8 KiB · 888e6f5 Raw
121 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * PIC32 RNG driver4 *5 * Joshua Henderson <joshua.henderson@microchip.com>6 * Copyright (C) 2016 Microchip Technology Inc.  All rights reserved.7 */8 9#include <linux/clk.h>10#include <linux/clkdev.h>11#include <linux/err.h>12#include <linux/hw_random.h>13#include <linux/io.h>14#include <linux/kernel.h>15#include <linux/mod_devicetable.h>16#include <linux/module.h>17#include <linux/platform_device.h>18#include <linux/slab.h>19 20#define RNGCON		0x0421#define TRNGEN		BIT(8)22#define TRNGMOD		BIT(11)23#define RNGSEED1	0x1824#define RNGSEED2	0x1C25#define RNGRCNT		0x2026#define RCNT_MASK	0x7F27 28struct pic32_rng {29	void __iomem	*base;30	struct hwrng	rng;31};32 33/*34 * The TRNG can generate up to 24Mbps. This is a timeout that should be safe35 * enough given the instructions in the loop and that the TRNG may not always36 * be at maximum rate.37 */38#define RNG_TIMEOUT 50039 40static int pic32_rng_init(struct hwrng *rng)41{42	struct pic32_rng *priv = container_of(rng, struct pic32_rng, rng);43 44	/* enable TRNG in enhanced mode */45	writel(TRNGEN | TRNGMOD, priv->base + RNGCON);46	return 0;47}48 49static int pic32_rng_read(struct hwrng *rng, void *buf, size_t max,50			  bool wait)51{52	struct pic32_rng *priv = container_of(rng, struct pic32_rng, rng);53	u64 *data = buf;54	u32 t;55	unsigned int timeout = RNG_TIMEOUT;56 57	do {58		t = readl(priv->base + RNGRCNT) & RCNT_MASK;59		if (t == 64) {60			/* TRNG value comes through the seed registers */61			*data = ((u64)readl(priv->base + RNGSEED2) << 32) +62				readl(priv->base + RNGSEED1);63			return 8;64		}65	} while (wait && --timeout);66 67	return -EIO;68}69 70static void pic32_rng_cleanup(struct hwrng *rng)71{72	struct pic32_rng *priv = container_of(rng, struct pic32_rng, rng);73 74	writel(0, priv->base + RNGCON);75}76 77static int pic32_rng_probe(struct platform_device *pdev)78{79	struct pic32_rng *priv;80	struct clk *clk;81 82	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);83	if (!priv)84		return -ENOMEM;85 86	priv->base = devm_platform_ioremap_resource(pdev, 0);87	if (IS_ERR(priv->base))88		return PTR_ERR(priv->base);89 90	clk = devm_clk_get_enabled(&pdev->dev, NULL);91	if (IS_ERR(clk))92		return PTR_ERR(clk);93 94	priv->rng.name = pdev->name;95	priv->rng.init = pic32_rng_init;96	priv->rng.read = pic32_rng_read;97	priv->rng.cleanup = pic32_rng_cleanup;98 99	return devm_hwrng_register(&pdev->dev, &priv->rng);100}101 102static const struct of_device_id pic32_rng_of_match[] __maybe_unused = {103	{ .compatible	= "microchip,pic32mzda-rng", },104	{ /* sentinel */ }105};106MODULE_DEVICE_TABLE(of, pic32_rng_of_match);107 108static struct platform_driver pic32_rng_driver = {109	.probe		= pic32_rng_probe,110	.driver		= {111		.name	= "pic32-rng",112		.of_match_table = pic32_rng_of_match,113	},114};115 116module_platform_driver(pic32_rng_driver);117 118MODULE_LICENSE("GPL");119MODULE_AUTHOR("Joshua Henderson <joshua.henderson@microchip.com>");120MODULE_DESCRIPTION("Microchip PIC32 RNG Driver");121