1cb435fa6SAtte Tommiska // SPDX-License-Identifier: GPL-2.0 2cb435fa6SAtte Tommiska /* Copyright (C) 2020 Xiphera Ltd. */ 3cb435fa6SAtte Tommiska 4cb435fa6SAtte Tommiska #include <linux/kernel.h> 5cb435fa6SAtte Tommiska #include <linux/module.h> 6cb435fa6SAtte Tommiska #include <linux/mod_devicetable.h> 7cb435fa6SAtte Tommiska #include <linux/err.h> 8cb435fa6SAtte Tommiska #include <linux/io.h> 9cb435fa6SAtte Tommiska #include <linux/hw_random.h> 10cb435fa6SAtte Tommiska #include <linux/of_device.h> 11cb435fa6SAtte Tommiska #include <linux/platform_device.h> 12cb435fa6SAtte Tommiska #include <linux/delay.h> 13cb435fa6SAtte Tommiska 14cb435fa6SAtte Tommiska #define CONTROL_REG 0x00000000 15cb435fa6SAtte Tommiska #define STATUS_REG 0x00000004 16cb435fa6SAtte Tommiska #define RAND_REG 0x00000000 17cb435fa6SAtte Tommiska 18cb435fa6SAtte Tommiska #define HOST_TO_TRNG_RESET 0x00000001 19cb435fa6SAtte Tommiska #define HOST_TO_TRNG_RELEASE_RESET 0x00000002 20cb435fa6SAtte Tommiska #define HOST_TO_TRNG_ENABLE 0x80000000 21cb435fa6SAtte Tommiska #define HOST_TO_TRNG_ZEROIZE 0x80000004 22cb435fa6SAtte Tommiska #define HOST_TO_TRNG_ACK_ZEROIZE 0x80000008 23cb435fa6SAtte Tommiska #define HOST_TO_TRNG_READ 0x8000000F 24cb435fa6SAtte Tommiska 25cb435fa6SAtte Tommiska /* trng statuses */ 26cb435fa6SAtte Tommiska #define TRNG_ACK_RESET 0x000000AC 27cb435fa6SAtte Tommiska #define TRNG_SUCCESSFUL_STARTUP 0x00000057 28cb435fa6SAtte Tommiska #define TRNG_FAILED_STARTUP 0x000000FA 29cb435fa6SAtte Tommiska #define TRNG_NEW_RAND_AVAILABLE 0x000000ED 30cb435fa6SAtte Tommiska 31cb435fa6SAtte Tommiska struct xiphera_trng { 32cb435fa6SAtte Tommiska void __iomem *mem; 33cb435fa6SAtte Tommiska struct hwrng rng; 34cb435fa6SAtte Tommiska }; 35cb435fa6SAtte Tommiska 36cb435fa6SAtte Tommiska static int xiphera_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait) 37cb435fa6SAtte Tommiska { 38cb435fa6SAtte Tommiska struct xiphera_trng *trng = container_of(rng, struct xiphera_trng, rng); 39cb435fa6SAtte Tommiska int ret = 0; 40cb435fa6SAtte Tommiska 41cb435fa6SAtte Tommiska while (max >= sizeof(u32)) { 42cb435fa6SAtte Tommiska /* check for data */ 43cb435fa6SAtte Tommiska if (readl(trng->mem + STATUS_REG) == TRNG_NEW_RAND_AVAILABLE) { 44cb435fa6SAtte Tommiska *(u32 *)buf = readl(trng->mem + RAND_REG); 45cb435fa6SAtte Tommiska /* 46cb435fa6SAtte Tommiska * Inform the trng of the read 47cb435fa6SAtte Tommiska * and re-enable it to produce a new random number 48cb435fa6SAtte Tommiska */ 49cb435fa6SAtte Tommiska writel(HOST_TO_TRNG_READ, trng->mem + CONTROL_REG); 50cb435fa6SAtte Tommiska writel(HOST_TO_TRNG_ENABLE, trng->mem + CONTROL_REG); 51cb435fa6SAtte Tommiska ret += sizeof(u32); 52cb435fa6SAtte Tommiska buf += sizeof(u32); 53cb435fa6SAtte Tommiska max -= sizeof(u32); 54cb435fa6SAtte Tommiska } else { 55cb435fa6SAtte Tommiska break; 56cb435fa6SAtte Tommiska } 57cb435fa6SAtte Tommiska } 58cb435fa6SAtte Tommiska return ret; 59cb435fa6SAtte Tommiska } 60cb435fa6SAtte Tommiska 61cb435fa6SAtte Tommiska static int xiphera_trng_probe(struct platform_device *pdev) 62cb435fa6SAtte Tommiska { 63cb435fa6SAtte Tommiska int ret; 64cb435fa6SAtte Tommiska struct xiphera_trng *trng; 65cb435fa6SAtte Tommiska struct device *dev = &pdev->dev; 66cb435fa6SAtte Tommiska struct resource *res; 67cb435fa6SAtte Tommiska 68cb435fa6SAtte Tommiska trng = devm_kzalloc(dev, sizeof(*trng), GFP_KERNEL); 69cb435fa6SAtte Tommiska if (!trng) 70cb435fa6SAtte Tommiska return -ENOMEM; 71cb435fa6SAtte Tommiska 72cb435fa6SAtte Tommiska res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 73cb435fa6SAtte Tommiska trng->mem = devm_ioremap_resource(dev, res); 74cb435fa6SAtte Tommiska if (IS_ERR(trng->mem)) 75cb435fa6SAtte Tommiska return PTR_ERR(trng->mem); 76cb435fa6SAtte Tommiska 77cb435fa6SAtte Tommiska /* 78cb435fa6SAtte Tommiska * the trng needs to be reset first which might not happen in time, 79cb435fa6SAtte Tommiska * hence we incorporate a small delay to ensure proper behaviour 80cb435fa6SAtte Tommiska */ 81cb435fa6SAtte Tommiska writel(HOST_TO_TRNG_RESET, trng->mem + CONTROL_REG); 82cb435fa6SAtte Tommiska usleep_range(100, 200); 83cb435fa6SAtte Tommiska 84cb435fa6SAtte Tommiska if (readl(trng->mem + STATUS_REG) != TRNG_ACK_RESET) { 85cb435fa6SAtte Tommiska /* 86cb435fa6SAtte Tommiska * there is a small chance the trng is just not ready yet, 87cb435fa6SAtte Tommiska * so we try one more time. If the second time fails, we give up 88cb435fa6SAtte Tommiska */ 89cb435fa6SAtte Tommiska usleep_range(100, 200); 90cb435fa6SAtte Tommiska if (readl(trng->mem + STATUS_REG) != TRNG_ACK_RESET) { 91cb435fa6SAtte Tommiska dev_err(dev, "failed to reset the trng ip\n"); 92cb435fa6SAtte Tommiska return -ENODEV; 93cb435fa6SAtte Tommiska } 94cb435fa6SAtte Tommiska } 95cb435fa6SAtte Tommiska 96cb435fa6SAtte Tommiska /* 97cb435fa6SAtte Tommiska * once again, to ensure proper behaviour we sleep 98cb435fa6SAtte Tommiska * for a while after zeroizing the trng 99cb435fa6SAtte Tommiska */ 100cb435fa6SAtte Tommiska writel(HOST_TO_TRNG_RELEASE_RESET, trng->mem + CONTROL_REG); 101cb435fa6SAtte Tommiska writel(HOST_TO_TRNG_ENABLE, trng->mem + CONTROL_REG); 102cb435fa6SAtte Tommiska writel(HOST_TO_TRNG_ZEROIZE, trng->mem + CONTROL_REG); 103cb435fa6SAtte Tommiska msleep(20); 104cb435fa6SAtte Tommiska 105cb435fa6SAtte Tommiska if (readl(trng->mem + STATUS_REG) != TRNG_SUCCESSFUL_STARTUP) { 106cb435fa6SAtte Tommiska /* diagnose the reason for the failure */ 107cb435fa6SAtte Tommiska if (readl(trng->mem + STATUS_REG) == TRNG_FAILED_STARTUP) { 108cb435fa6SAtte Tommiska dev_err(dev, "trng ip startup-tests failed\n"); 109cb435fa6SAtte Tommiska return -ENODEV; 110cb435fa6SAtte Tommiska } 111cb435fa6SAtte Tommiska dev_err(dev, "startup-tests yielded no response\n"); 112cb435fa6SAtte Tommiska return -ENODEV; 113cb435fa6SAtte Tommiska } 114cb435fa6SAtte Tommiska 115cb435fa6SAtte Tommiska writel(HOST_TO_TRNG_ACK_ZEROIZE, trng->mem + CONTROL_REG); 116cb435fa6SAtte Tommiska 117cb435fa6SAtte Tommiska trng->rng.name = pdev->name; 118cb435fa6SAtte Tommiska trng->rng.read = xiphera_trng_read; 119cb435fa6SAtte Tommiska trng->rng.quality = 900; 120cb435fa6SAtte Tommiska 121cb435fa6SAtte Tommiska ret = devm_hwrng_register(dev, &trng->rng); 122cb435fa6SAtte Tommiska if (ret) { 123cb435fa6SAtte Tommiska dev_err(dev, "failed to register rng device: %d\n", ret); 124cb435fa6SAtte Tommiska return ret; 125cb435fa6SAtte Tommiska } 126cb435fa6SAtte Tommiska 127cb435fa6SAtte Tommiska platform_set_drvdata(pdev, trng); 128cb435fa6SAtte Tommiska 129cb435fa6SAtte Tommiska return 0; 130cb435fa6SAtte Tommiska } 131cb435fa6SAtte Tommiska 132cb435fa6SAtte Tommiska static const struct of_device_id xiphera_trng_of_match[] = { 133cb435fa6SAtte Tommiska { .compatible = "xiphera,xip8001b-trng", }, 134cb435fa6SAtte Tommiska {}, 135cb435fa6SAtte Tommiska }; 136cb435fa6SAtte Tommiska MODULE_DEVICE_TABLE(of, xiphera_trng_of_match); 137cb435fa6SAtte Tommiska 138cb435fa6SAtte Tommiska static struct platform_driver xiphera_trng_driver = { 139cb435fa6SAtte Tommiska .driver = { 140cb435fa6SAtte Tommiska .name = "xiphera-trng", 141cb435fa6SAtte Tommiska .of_match_table = xiphera_trng_of_match, 142cb435fa6SAtte Tommiska }, 143cb435fa6SAtte Tommiska .probe = xiphera_trng_probe, 144cb435fa6SAtte Tommiska }; 145cb435fa6SAtte Tommiska 146cb435fa6SAtte Tommiska module_platform_driver(xiphera_trng_driver); 147cb435fa6SAtte Tommiska 148cb435fa6SAtte Tommiska MODULE_LICENSE("GPL"); 149cb435fa6SAtte Tommiska MODULE_AUTHOR("Atte Tommiska"); 150cb435fa6SAtte Tommiska MODULE_DESCRIPTION("Xiphera FPGA-based true random number generator driver"); 151