104dc82e1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2730d02e2SJoshua Henderson /* 3730d02e2SJoshua Henderson * PIC32 RNG driver 4730d02e2SJoshua Henderson * 5730d02e2SJoshua Henderson * Joshua Henderson <joshua.henderson@microchip.com> 6730d02e2SJoshua Henderson * Copyright (C) 2016 Microchip Technology Inc. All rights reserved. 7730d02e2SJoshua Henderson */ 8730d02e2SJoshua Henderson 9730d02e2SJoshua Henderson #include <linux/clk.h> 10730d02e2SJoshua Henderson #include <linux/clkdev.h> 11730d02e2SJoshua Henderson #include <linux/err.h> 12730d02e2SJoshua Henderson #include <linux/hw_random.h> 13730d02e2SJoshua Henderson #include <linux/io.h> 14730d02e2SJoshua Henderson #include <linux/kernel.h> 15730d02e2SJoshua Henderson #include <linux/module.h> 16730d02e2SJoshua Henderson #include <linux/of.h> 17730d02e2SJoshua Henderson #include <linux/of_device.h> 18730d02e2SJoshua Henderson #include <linux/platform_device.h> 19730d02e2SJoshua Henderson #include <linux/slab.h> 20730d02e2SJoshua Henderson 21730d02e2SJoshua Henderson #define RNGCON 0x04 22730d02e2SJoshua Henderson #define TRNGEN BIT(8) 23730d02e2SJoshua Henderson #define PRNGEN BIT(9) 24730d02e2SJoshua Henderson #define PRNGCONT BIT(10) 25730d02e2SJoshua Henderson #define TRNGMOD BIT(11) 26730d02e2SJoshua Henderson #define SEEDLOAD BIT(12) 27730d02e2SJoshua Henderson #define RNGPOLY1 0x08 28730d02e2SJoshua Henderson #define RNGPOLY2 0x0C 29730d02e2SJoshua Henderson #define RNGNUMGEN1 0x10 30730d02e2SJoshua Henderson #define RNGNUMGEN2 0x14 31730d02e2SJoshua Henderson #define RNGSEED1 0x18 32730d02e2SJoshua Henderson #define RNGSEED2 0x1C 33730d02e2SJoshua Henderson #define RNGRCNT 0x20 34730d02e2SJoshua Henderson #define RCNT_MASK 0x7F 35730d02e2SJoshua Henderson 36730d02e2SJoshua Henderson struct pic32_rng { 37730d02e2SJoshua Henderson void __iomem *base; 38730d02e2SJoshua Henderson struct hwrng rng; 39730d02e2SJoshua Henderson }; 40730d02e2SJoshua Henderson 41730d02e2SJoshua Henderson /* 42730d02e2SJoshua Henderson * The TRNG can generate up to 24Mbps. This is a timeout that should be safe 43730d02e2SJoshua Henderson * enough given the instructions in the loop and that the TRNG may not always 44730d02e2SJoshua Henderson * be at maximum rate. 45730d02e2SJoshua Henderson */ 46730d02e2SJoshua Henderson #define RNG_TIMEOUT 500 47730d02e2SJoshua Henderson 48730d02e2SJoshua Henderson static int pic32_rng_read(struct hwrng *rng, void *buf, size_t max, 49730d02e2SJoshua Henderson bool wait) 50730d02e2SJoshua Henderson { 51730d02e2SJoshua Henderson struct pic32_rng *priv = container_of(rng, struct pic32_rng, rng); 52730d02e2SJoshua Henderson u64 *data = buf; 53730d02e2SJoshua Henderson u32 t; 54730d02e2SJoshua Henderson unsigned int timeout = RNG_TIMEOUT; 55730d02e2SJoshua Henderson 56730d02e2SJoshua Henderson do { 57730d02e2SJoshua Henderson t = readl(priv->base + RNGRCNT) & RCNT_MASK; 58730d02e2SJoshua Henderson if (t == 64) { 59730d02e2SJoshua Henderson /* TRNG value comes through the seed registers */ 60730d02e2SJoshua Henderson *data = ((u64)readl(priv->base + RNGSEED2) << 32) + 61730d02e2SJoshua Henderson readl(priv->base + RNGSEED1); 62730d02e2SJoshua Henderson return 8; 63730d02e2SJoshua Henderson } 64730d02e2SJoshua Henderson } while (wait && --timeout); 65730d02e2SJoshua Henderson 66730d02e2SJoshua Henderson return -EIO; 67730d02e2SJoshua Henderson } 68730d02e2SJoshua Henderson 69730d02e2SJoshua Henderson static int pic32_rng_probe(struct platform_device *pdev) 70730d02e2SJoshua Henderson { 71730d02e2SJoshua Henderson struct pic32_rng *priv; 72*6755ad74SMartin Kaiser struct clk *clk; 73730d02e2SJoshua Henderson u32 v; 74730d02e2SJoshua Henderson int ret; 75730d02e2SJoshua Henderson 76730d02e2SJoshua Henderson priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 77730d02e2SJoshua Henderson if (!priv) 78730d02e2SJoshua Henderson return -ENOMEM; 79730d02e2SJoshua Henderson 8064b7bf13SYueHaibing priv->base = devm_platform_ioremap_resource(pdev, 0); 81730d02e2SJoshua Henderson if (IS_ERR(priv->base)) 82730d02e2SJoshua Henderson return PTR_ERR(priv->base); 83730d02e2SJoshua Henderson 84*6755ad74SMartin Kaiser clk = devm_clk_get_enabled(&pdev->dev, NULL); 85*6755ad74SMartin Kaiser if (IS_ERR(clk)) 86*6755ad74SMartin Kaiser return PTR_ERR(clk); 87730d02e2SJoshua Henderson 88730d02e2SJoshua Henderson /* enable TRNG in enhanced mode */ 89730d02e2SJoshua Henderson v = TRNGEN | TRNGMOD; 90730d02e2SJoshua Henderson writel(v, priv->base + RNGCON); 91730d02e2SJoshua Henderson 92730d02e2SJoshua Henderson priv->rng.name = pdev->name; 93730d02e2SJoshua Henderson priv->rng.read = pic32_rng_read; 94730d02e2SJoshua Henderson 957ea39973STian Tao ret = devm_hwrng_register(&pdev->dev, &priv->rng); 96730d02e2SJoshua Henderson if (ret) 97*6755ad74SMartin Kaiser return ret; 98730d02e2SJoshua Henderson 99730d02e2SJoshua Henderson platform_set_drvdata(pdev, priv); 100730d02e2SJoshua Henderson 101730d02e2SJoshua Henderson return 0; 102730d02e2SJoshua Henderson } 103730d02e2SJoshua Henderson 104730d02e2SJoshua Henderson static int pic32_rng_remove(struct platform_device *pdev) 105730d02e2SJoshua Henderson { 106730d02e2SJoshua Henderson struct pic32_rng *rng = platform_get_drvdata(pdev); 107730d02e2SJoshua Henderson 108730d02e2SJoshua Henderson writel(0, rng->base + RNGCON); 109730d02e2SJoshua Henderson return 0; 110730d02e2SJoshua Henderson } 111730d02e2SJoshua Henderson 112e05231a5SHerbert Xu static const struct of_device_id pic32_rng_of_match[] __maybe_unused = { 113730d02e2SJoshua Henderson { .compatible = "microchip,pic32mzda-rng", }, 114730d02e2SJoshua Henderson { /* sentinel */ } 115730d02e2SJoshua Henderson }; 116730d02e2SJoshua Henderson MODULE_DEVICE_TABLE(of, pic32_rng_of_match); 117730d02e2SJoshua Henderson 118730d02e2SJoshua Henderson static struct platform_driver pic32_rng_driver = { 119730d02e2SJoshua Henderson .probe = pic32_rng_probe, 120730d02e2SJoshua Henderson .remove = pic32_rng_remove, 121730d02e2SJoshua Henderson .driver = { 122730d02e2SJoshua Henderson .name = "pic32-rng", 123730d02e2SJoshua Henderson .of_match_table = of_match_ptr(pic32_rng_of_match), 124730d02e2SJoshua Henderson }, 125730d02e2SJoshua Henderson }; 126730d02e2SJoshua Henderson 127730d02e2SJoshua Henderson module_platform_driver(pic32_rng_driver); 128730d02e2SJoshua Henderson 129730d02e2SJoshua Henderson MODULE_LICENSE("GPL"); 130730d02e2SJoshua Henderson MODULE_AUTHOR("Joshua Henderson <joshua.henderson@microchip.com>"); 131730d02e2SJoshua Henderson MODULE_DESCRIPTION("Microchip PIC32 RNG Driver"); 132