Path: blob/master/drivers/char/hw_random/bcm74110-rng.c
29269 views
// SPDX-License-Identifier: GPL-2.01/*2* Copyright (c) 2024 Broadcom3*/45#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt67#include <linux/module.h>8#include <linux/mod_devicetable.h>9#include <linux/kernel.h>10#include <linux/io.h>11#include <linux/delay.h>12#include <linux/platform_device.h>13#include <linux/random.h>14#include <linux/hw_random.h>1516#define HOST_REV_ID 0x0017#define HOST_FIFO_DEPTH 0x0418#define HOST_FIFO_COUNT 0x0819#define HOST_FIFO_THRESHOLD 0x0c20#define HOST_FIFO_DATA 0x102122#define HOST_FIFO_COUNT_MASK 0xffff2324/* Delay range in microseconds */25#define FIFO_DELAY_MIN_US 326#define FIFO_DELAY_MAX_US 727#define FIFO_DELAY_MAX_COUNT 102829struct bcm74110_priv {30void __iomem *base;31};3233static inline int bcm74110_rng_fifo_count(void __iomem *mem)34{35return readl_relaxed(mem) & HOST_FIFO_COUNT_MASK;36}3738static int bcm74110_rng_read(struct hwrng *rng, void *buf, size_t max,39bool wait)40{41struct bcm74110_priv *priv = (struct bcm74110_priv *)rng->priv;42void __iomem *fc_addr = priv->base + HOST_FIFO_COUNT;43void __iomem *fd_addr = priv->base + HOST_FIFO_DATA;44unsigned underrun_count = 0;45u32 max_words = max / sizeof(u32);46u32 num_words;47unsigned i;4849/*50* We need to check how many words are available in the RNG FIFO. If51* there aren't any, we need to wait for some to become available.52*/53while ((num_words = bcm74110_rng_fifo_count(fc_addr)) == 0) {54if (!wait)55return 0;56/*57* As a precaution, limit how long we wait. If the FIFO doesn't58* refill within the allotted time, return 0 (=no data) to the59* caller.60*/61if (likely(underrun_count < FIFO_DELAY_MAX_COUNT))62usleep_range(FIFO_DELAY_MIN_US, FIFO_DELAY_MAX_US);63else64return 0;65underrun_count++;66}67if (num_words > max_words)68num_words = max_words;6970/* Bail early if we run out of random numbers unexpectedly */71for (i = 0; i < num_words && bcm74110_rng_fifo_count(fc_addr) > 0; i++)72((u32 *)buf)[i] = readl_relaxed(fd_addr);7374return i * sizeof(u32);75}7677static struct hwrng bcm74110_hwrng = {78.read = bcm74110_rng_read,79};8081static int bcm74110_rng_probe(struct platform_device *pdev)82{83struct device *dev = &pdev->dev;84struct bcm74110_priv *priv;85int rc;8687priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);88if (!priv)89return -ENOMEM;9091bcm74110_hwrng.name = pdev->name;92bcm74110_hwrng.priv = (unsigned long)priv;9394priv->base = devm_platform_ioremap_resource(pdev, 0);95if (IS_ERR(priv->base))96return PTR_ERR(priv->base);9798rc = devm_hwrng_register(dev, &bcm74110_hwrng);99if (rc)100dev_err(dev, "hwrng registration failed (%d)\n", rc);101else102dev_info(dev, "hwrng registered\n");103104return rc;105}106107static const struct of_device_id bcm74110_rng_match[] = {108{ .compatible = "brcm,bcm74110-rng", },109{},110};111MODULE_DEVICE_TABLE(of, bcm74110_rng_match);112113static struct platform_driver bcm74110_rng_driver = {114.driver = {115.name = KBUILD_MODNAME,116.of_match_table = bcm74110_rng_match,117},118.probe = bcm74110_rng_probe,119};120module_platform_driver(bcm74110_rng_driver);121122MODULE_AUTHOR("Markus Mayer <[email protected]>");123MODULE_DESCRIPTION("BCM 74110 Random Number Generator (RNG) driver");124MODULE_LICENSE("GPL v2");125126127