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