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 67cb435fa6SAtte Tommiska trng = devm_kzalloc(dev, sizeof(*trng), GFP_KERNEL); 68cb435fa6SAtte Tommiska if (!trng) 69cb435fa6SAtte Tommiska return -ENOMEM; 70cb435fa6SAtte Tommiska 71*8fb7bd31STian Tao trng->mem = devm_platform_ioremap_resource(pdev, 0); 72cb435fa6SAtte Tommiska if (IS_ERR(trng->mem)) 73cb435fa6SAtte Tommiska return PTR_ERR(trng->mem); 74cb435fa6SAtte Tommiska 75cb435fa6SAtte Tommiska /* 76cb435fa6SAtte Tommiska * the trng needs to be reset first which might not happen in time, 77cb435fa6SAtte Tommiska * hence we incorporate a small delay to ensure proper behaviour 78cb435fa6SAtte Tommiska */ 79cb435fa6SAtte Tommiska writel(HOST_TO_TRNG_RESET, trng->mem + CONTROL_REG); 80cb435fa6SAtte Tommiska usleep_range(100, 200); 81cb435fa6SAtte Tommiska 82cb435fa6SAtte Tommiska if (readl(trng->mem + STATUS_REG) != TRNG_ACK_RESET) { 83cb435fa6SAtte Tommiska /* 84cb435fa6SAtte Tommiska * there is a small chance the trng is just not ready yet, 85cb435fa6SAtte Tommiska * so we try one more time. If the second time fails, we give up 86cb435fa6SAtte Tommiska */ 87cb435fa6SAtte Tommiska usleep_range(100, 200); 88cb435fa6SAtte Tommiska if (readl(trng->mem + STATUS_REG) != TRNG_ACK_RESET) { 89cb435fa6SAtte Tommiska dev_err(dev, "failed to reset the trng ip\n"); 90cb435fa6SAtte Tommiska return -ENODEV; 91cb435fa6SAtte Tommiska } 92cb435fa6SAtte Tommiska } 93cb435fa6SAtte Tommiska 94cb435fa6SAtte Tommiska /* 95cb435fa6SAtte Tommiska * once again, to ensure proper behaviour we sleep 96cb435fa6SAtte Tommiska * for a while after zeroizing the trng 97cb435fa6SAtte Tommiska */ 98cb435fa6SAtte Tommiska writel(HOST_TO_TRNG_RELEASE_RESET, trng->mem + CONTROL_REG); 99cb435fa6SAtte Tommiska writel(HOST_TO_TRNG_ENABLE, trng->mem + CONTROL_REG); 100cb435fa6SAtte Tommiska writel(HOST_TO_TRNG_ZEROIZE, trng->mem + CONTROL_REG); 101cb435fa6SAtte Tommiska msleep(20); 102cb435fa6SAtte Tommiska 103cb435fa6SAtte Tommiska if (readl(trng->mem + STATUS_REG) != TRNG_SUCCESSFUL_STARTUP) { 104cb435fa6SAtte Tommiska /* diagnose the reason for the failure */ 105cb435fa6SAtte Tommiska if (readl(trng->mem + STATUS_REG) == TRNG_FAILED_STARTUP) { 106cb435fa6SAtte Tommiska dev_err(dev, "trng ip startup-tests failed\n"); 107cb435fa6SAtte Tommiska return -ENODEV; 108cb435fa6SAtte Tommiska } 109cb435fa6SAtte Tommiska dev_err(dev, "startup-tests yielded no response\n"); 110cb435fa6SAtte Tommiska return -ENODEV; 111cb435fa6SAtte Tommiska } 112cb435fa6SAtte Tommiska 113cb435fa6SAtte Tommiska writel(HOST_TO_TRNG_ACK_ZEROIZE, trng->mem + CONTROL_REG); 114cb435fa6SAtte Tommiska 115cb435fa6SAtte Tommiska trng->rng.name = pdev->name; 116cb435fa6SAtte Tommiska trng->rng.read = xiphera_trng_read; 117cb435fa6SAtte Tommiska trng->rng.quality = 900; 118cb435fa6SAtte Tommiska 119cb435fa6SAtte Tommiska ret = devm_hwrng_register(dev, &trng->rng); 120cb435fa6SAtte Tommiska if (ret) { 121cb435fa6SAtte Tommiska dev_err(dev, "failed to register rng device: %d\n", ret); 122cb435fa6SAtte Tommiska return ret; 123cb435fa6SAtte Tommiska } 124cb435fa6SAtte Tommiska 125cb435fa6SAtte Tommiska platform_set_drvdata(pdev, trng); 126cb435fa6SAtte Tommiska 127cb435fa6SAtte Tommiska return 0; 128cb435fa6SAtte Tommiska } 129cb435fa6SAtte Tommiska 130cb435fa6SAtte Tommiska static const struct of_device_id xiphera_trng_of_match[] = { 131cb435fa6SAtte Tommiska { .compatible = "xiphera,xip8001b-trng", }, 132cb435fa6SAtte Tommiska {}, 133cb435fa6SAtte Tommiska }; 134cb435fa6SAtte Tommiska MODULE_DEVICE_TABLE(of, xiphera_trng_of_match); 135cb435fa6SAtte Tommiska 136cb435fa6SAtte Tommiska static struct platform_driver xiphera_trng_driver = { 137cb435fa6SAtte Tommiska .driver = { 138cb435fa6SAtte Tommiska .name = "xiphera-trng", 139cb435fa6SAtte Tommiska .of_match_table = xiphera_trng_of_match, 140cb435fa6SAtte Tommiska }, 141cb435fa6SAtte Tommiska .probe = xiphera_trng_probe, 142cb435fa6SAtte Tommiska }; 143cb435fa6SAtte Tommiska 144cb435fa6SAtte Tommiska module_platform_driver(xiphera_trng_driver); 145cb435fa6SAtte Tommiska 146cb435fa6SAtte Tommiska MODULE_LICENSE("GPL"); 147cb435fa6SAtte Tommiska MODULE_AUTHOR("Atte Tommiska"); 148cb435fa6SAtte Tommiska MODULE_DESCRIPTION("Xiphera FPGA-based true random number generator driver"); 149