1*903e6adaSDavid Yang // SPDX-License-Identifier: GPL-2.0-or-later OR MIT 2*903e6adaSDavid Yang /* 3*903e6adaSDavid Yang * Copyright (c) 2023 David Yang 4*903e6adaSDavid Yang */ 5*903e6adaSDavid Yang 6*903e6adaSDavid Yang #include <linux/err.h> 7*903e6adaSDavid Yang #include <linux/hw_random.h> 8*903e6adaSDavid Yang #include <linux/io.h> 9*903e6adaSDavid Yang #include <linux/iopoll.h> 10*903e6adaSDavid Yang #include <linux/kernel.h> 11*903e6adaSDavid Yang #include <linux/mod_devicetable.h> 12*903e6adaSDavid Yang #include <linux/module.h> 13*903e6adaSDavid Yang #include <linux/platform_device.h> 14*903e6adaSDavid Yang 15*903e6adaSDavid Yang #define RNG_CTRL 0x0 16*903e6adaSDavid Yang #define RNG_SOURCE GENMASK(1, 0) 17*903e6adaSDavid Yang #define DROP_ENABLE BIT(5) 18*903e6adaSDavid Yang #define POST_PROCESS_ENABLE BIT(7) 19*903e6adaSDavid Yang #define POST_PROCESS_DEPTH GENMASK(15, 8) 20*903e6adaSDavid Yang #define RNG_NUMBER 0x4 21*903e6adaSDavid Yang #define RNG_STAT 0x8 22*903e6adaSDavid Yang #define DATA_COUNT GENMASK(2, 0) /* max 4 */ 23*903e6adaSDavid Yang 24*903e6adaSDavid Yang struct histb_rng_priv { 25*903e6adaSDavid Yang struct hwrng rng; 26*903e6adaSDavid Yang void __iomem *base; 27*903e6adaSDavid Yang }; 28*903e6adaSDavid Yang 29*903e6adaSDavid Yang /* 30*903e6adaSDavid Yang * Observed: 31*903e6adaSDavid Yang * depth = 1 -> ~1ms 32*903e6adaSDavid Yang * depth = 255 -> ~16ms 33*903e6adaSDavid Yang */ 34*903e6adaSDavid Yang static int histb_rng_wait(void __iomem *base) 35*903e6adaSDavid Yang { 36*903e6adaSDavid Yang u32 val; 37*903e6adaSDavid Yang 38*903e6adaSDavid Yang return readl_relaxed_poll_timeout(base + RNG_STAT, val, 39*903e6adaSDavid Yang val & DATA_COUNT, 1000, 30 * 1000); 40*903e6adaSDavid Yang } 41*903e6adaSDavid Yang 42*903e6adaSDavid Yang static void histb_rng_init(void __iomem *base, unsigned int depth) 43*903e6adaSDavid Yang { 44*903e6adaSDavid Yang u32 val; 45*903e6adaSDavid Yang 46*903e6adaSDavid Yang val = readl_relaxed(base + RNG_CTRL); 47*903e6adaSDavid Yang 48*903e6adaSDavid Yang val &= ~RNG_SOURCE; 49*903e6adaSDavid Yang val |= 2; 50*903e6adaSDavid Yang 51*903e6adaSDavid Yang val &= ~POST_PROCESS_DEPTH; 52*903e6adaSDavid Yang val |= min(depth, 0xffu) << 8; 53*903e6adaSDavid Yang 54*903e6adaSDavid Yang val |= POST_PROCESS_ENABLE; 55*903e6adaSDavid Yang val |= DROP_ENABLE; 56*903e6adaSDavid Yang 57*903e6adaSDavid Yang writel_relaxed(val, base + RNG_CTRL); 58*903e6adaSDavid Yang } 59*903e6adaSDavid Yang 60*903e6adaSDavid Yang static int histb_rng_read(struct hwrng *rng, void *data, size_t max, bool wait) 61*903e6adaSDavid Yang { 62*903e6adaSDavid Yang struct histb_rng_priv *priv = container_of(rng, typeof(*priv), rng); 63*903e6adaSDavid Yang void __iomem *base = priv->base; 64*903e6adaSDavid Yang 65*903e6adaSDavid Yang for (int i = 0; i < max; i += sizeof(u32)) { 66*903e6adaSDavid Yang if (!(readl_relaxed(base + RNG_STAT) & DATA_COUNT)) { 67*903e6adaSDavid Yang if (!wait) 68*903e6adaSDavid Yang return i; 69*903e6adaSDavid Yang if (histb_rng_wait(base)) { 70*903e6adaSDavid Yang pr_err("failed to generate random number, generated %d\n", 71*903e6adaSDavid Yang i); 72*903e6adaSDavid Yang return i ? i : -ETIMEDOUT; 73*903e6adaSDavid Yang } 74*903e6adaSDavid Yang } 75*903e6adaSDavid Yang *(u32 *) (data + i) = readl_relaxed(base + RNG_NUMBER); 76*903e6adaSDavid Yang } 77*903e6adaSDavid Yang 78*903e6adaSDavid Yang return max; 79*903e6adaSDavid Yang } 80*903e6adaSDavid Yang 81*903e6adaSDavid Yang static unsigned int histb_rng_get_depth(void __iomem *base) 82*903e6adaSDavid Yang { 83*903e6adaSDavid Yang return (readl_relaxed(base + RNG_CTRL) & POST_PROCESS_DEPTH) >> 8; 84*903e6adaSDavid Yang } 85*903e6adaSDavid Yang 86*903e6adaSDavid Yang static ssize_t 87*903e6adaSDavid Yang depth_show(struct device *dev, struct device_attribute *attr, char *buf) 88*903e6adaSDavid Yang { 89*903e6adaSDavid Yang struct histb_rng_priv *priv = dev_get_drvdata(dev); 90*903e6adaSDavid Yang void __iomem *base = priv->base; 91*903e6adaSDavid Yang 92*903e6adaSDavid Yang return sprintf(buf, "%d\n", histb_rng_get_depth(base)); 93*903e6adaSDavid Yang } 94*903e6adaSDavid Yang 95*903e6adaSDavid Yang static ssize_t 96*903e6adaSDavid Yang depth_store(struct device *dev, struct device_attribute *attr, 97*903e6adaSDavid Yang const char *buf, size_t count) 98*903e6adaSDavid Yang { 99*903e6adaSDavid Yang struct histb_rng_priv *priv = dev_get_drvdata(dev); 100*903e6adaSDavid Yang void __iomem *base = priv->base; 101*903e6adaSDavid Yang unsigned int depth; 102*903e6adaSDavid Yang 103*903e6adaSDavid Yang if (kstrtouint(buf, 0, &depth)) 104*903e6adaSDavid Yang return -ERANGE; 105*903e6adaSDavid Yang 106*903e6adaSDavid Yang histb_rng_init(base, depth); 107*903e6adaSDavid Yang return count; 108*903e6adaSDavid Yang } 109*903e6adaSDavid Yang 110*903e6adaSDavid Yang static DEVICE_ATTR_RW(depth); 111*903e6adaSDavid Yang 112*903e6adaSDavid Yang static struct attribute *histb_rng_attrs[] = { 113*903e6adaSDavid Yang &dev_attr_depth.attr, 114*903e6adaSDavid Yang NULL, 115*903e6adaSDavid Yang }; 116*903e6adaSDavid Yang 117*903e6adaSDavid Yang ATTRIBUTE_GROUPS(histb_rng); 118*903e6adaSDavid Yang 119*903e6adaSDavid Yang static int histb_rng_probe(struct platform_device *pdev) 120*903e6adaSDavid Yang { 121*903e6adaSDavid Yang struct device *dev = &pdev->dev; 122*903e6adaSDavid Yang struct histb_rng_priv *priv; 123*903e6adaSDavid Yang void __iomem *base; 124*903e6adaSDavid Yang int ret; 125*903e6adaSDavid Yang 126*903e6adaSDavid Yang priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 127*903e6adaSDavid Yang if (!priv) 128*903e6adaSDavid Yang return -ENOMEM; 129*903e6adaSDavid Yang 130*903e6adaSDavid Yang base = devm_platform_ioremap_resource(pdev, 0); 131*903e6adaSDavid Yang if (IS_ERR(base)) 132*903e6adaSDavid Yang return PTR_ERR(base); 133*903e6adaSDavid Yang 134*903e6adaSDavid Yang histb_rng_init(base, 144); 135*903e6adaSDavid Yang if (histb_rng_wait(base)) { 136*903e6adaSDavid Yang dev_err(dev, "cannot bring up device\n"); 137*903e6adaSDavid Yang return -ENODEV; 138*903e6adaSDavid Yang } 139*903e6adaSDavid Yang 140*903e6adaSDavid Yang priv->base = base; 141*903e6adaSDavid Yang priv->rng.name = pdev->name; 142*903e6adaSDavid Yang priv->rng.read = histb_rng_read; 143*903e6adaSDavid Yang ret = devm_hwrng_register(dev, &priv->rng); 144*903e6adaSDavid Yang if (ret) { 145*903e6adaSDavid Yang dev_err(dev, "failed to register hwrng: %d\n", ret); 146*903e6adaSDavid Yang return ret; 147*903e6adaSDavid Yang } 148*903e6adaSDavid Yang 149*903e6adaSDavid Yang platform_set_drvdata(pdev, priv); 150*903e6adaSDavid Yang dev_set_drvdata(dev, priv); 151*903e6adaSDavid Yang return 0; 152*903e6adaSDavid Yang } 153*903e6adaSDavid Yang 154*903e6adaSDavid Yang static const struct of_device_id histb_rng_of_match[] = { 155*903e6adaSDavid Yang { .compatible = "hisilicon,histb-rng", }, 156*903e6adaSDavid Yang { } 157*903e6adaSDavid Yang }; 158*903e6adaSDavid Yang MODULE_DEVICE_TABLE(of, histb_rng_of_match); 159*903e6adaSDavid Yang 160*903e6adaSDavid Yang static struct platform_driver histb_rng_driver = { 161*903e6adaSDavid Yang .probe = histb_rng_probe, 162*903e6adaSDavid Yang .driver = { 163*903e6adaSDavid Yang .name = "histb-rng", 164*903e6adaSDavid Yang .of_match_table = histb_rng_of_match, 165*903e6adaSDavid Yang .dev_groups = histb_rng_groups, 166*903e6adaSDavid Yang }, 167*903e6adaSDavid Yang }; 168*903e6adaSDavid Yang 169*903e6adaSDavid Yang module_platform_driver(histb_rng_driver); 170*903e6adaSDavid Yang 171*903e6adaSDavid Yang MODULE_DESCRIPTION("Hisilicon STB random number generator driver"); 172*903e6adaSDavid Yang MODULE_LICENSE("Dual MIT/GPL"); 173*903e6adaSDavid Yang MODULE_AUTHOR("David Yang <mmyangfl@gmail.com>"); 174