1 /* 2 * PIC32 RNG driver 3 * 4 * Joshua Henderson <joshua.henderson@microchip.com> 5 * Copyright (C) 2016 Microchip Technology Inc. All rights reserved. 6 * 7 * This program is free software; you can distribute it and/or modify it 8 * under the terms of the GNU General Public License (Version 2) as 9 * published by the Free Software Foundation. 10 * 11 * This program is distributed in the hope it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * for more details. 15 */ 16 17 #include <linux/clk.h> 18 #include <linux/clkdev.h> 19 #include <linux/err.h> 20 #include <linux/hw_random.h> 21 #include <linux/io.h> 22 #include <linux/kernel.h> 23 #include <linux/module.h> 24 #include <linux/of.h> 25 #include <linux/of_device.h> 26 #include <linux/platform_device.h> 27 #include <linux/slab.h> 28 29 #define RNGCON 0x04 30 #define TRNGEN BIT(8) 31 #define PRNGEN BIT(9) 32 #define PRNGCONT BIT(10) 33 #define TRNGMOD BIT(11) 34 #define SEEDLOAD BIT(12) 35 #define RNGPOLY1 0x08 36 #define RNGPOLY2 0x0C 37 #define RNGNUMGEN1 0x10 38 #define RNGNUMGEN2 0x14 39 #define RNGSEED1 0x18 40 #define RNGSEED2 0x1C 41 #define RNGRCNT 0x20 42 #define RCNT_MASK 0x7F 43 44 struct pic32_rng { 45 void __iomem *base; 46 struct hwrng rng; 47 struct clk *clk; 48 }; 49 50 /* 51 * The TRNG can generate up to 24Mbps. This is a timeout that should be safe 52 * enough given the instructions in the loop and that the TRNG may not always 53 * be at maximum rate. 54 */ 55 #define RNG_TIMEOUT 500 56 57 static int pic32_rng_read(struct hwrng *rng, void *buf, size_t max, 58 bool wait) 59 { 60 struct pic32_rng *priv = container_of(rng, struct pic32_rng, rng); 61 u64 *data = buf; 62 u32 t; 63 unsigned int timeout = RNG_TIMEOUT; 64 65 do { 66 t = readl(priv->base + RNGRCNT) & RCNT_MASK; 67 if (t == 64) { 68 /* TRNG value comes through the seed registers */ 69 *data = ((u64)readl(priv->base + RNGSEED2) << 32) + 70 readl(priv->base + RNGSEED1); 71 return 8; 72 } 73 } while (wait && --timeout); 74 75 return -EIO; 76 } 77 78 static int pic32_rng_probe(struct platform_device *pdev) 79 { 80 struct pic32_rng *priv; 81 struct resource *res; 82 u32 v; 83 int ret; 84 85 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 86 if (!priv) 87 return -ENOMEM; 88 89 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 90 priv->base = devm_ioremap_resource(&pdev->dev, res); 91 if (IS_ERR(priv->base)) 92 return PTR_ERR(priv->base); 93 94 priv->clk = devm_clk_get(&pdev->dev, NULL); 95 if (IS_ERR(priv->clk)) 96 return PTR_ERR(priv->clk); 97 98 ret = clk_prepare_enable(priv->clk); 99 if (ret) 100 return ret; 101 102 /* enable TRNG in enhanced mode */ 103 v = TRNGEN | TRNGMOD; 104 writel(v, priv->base + RNGCON); 105 106 priv->rng.name = pdev->name; 107 priv->rng.read = pic32_rng_read; 108 109 ret = hwrng_register(&priv->rng); 110 if (ret) 111 goto err_register; 112 113 platform_set_drvdata(pdev, priv); 114 115 return 0; 116 117 err_register: 118 clk_disable_unprepare(priv->clk); 119 return ret; 120 } 121 122 static int pic32_rng_remove(struct platform_device *pdev) 123 { 124 struct pic32_rng *rng = platform_get_drvdata(pdev); 125 126 hwrng_unregister(&rng->rng); 127 writel(0, rng->base + RNGCON); 128 clk_disable_unprepare(rng->clk); 129 return 0; 130 } 131 132 static const struct of_device_id pic32_rng_of_match[] = { 133 { .compatible = "microchip,pic32mzda-rng", }, 134 { /* sentinel */ } 135 }; 136 MODULE_DEVICE_TABLE(of, pic32_rng_of_match); 137 138 static struct platform_driver pic32_rng_driver = { 139 .probe = pic32_rng_probe, 140 .remove = pic32_rng_remove, 141 .driver = { 142 .name = "pic32-rng", 143 .of_match_table = of_match_ptr(pic32_rng_of_match), 144 }, 145 }; 146 147 module_platform_driver(pic32_rng_driver); 148 149 MODULE_LICENSE("GPL"); 150 MODULE_AUTHOR("Joshua Henderson <joshua.henderson@microchip.com>"); 151 MODULE_DESCRIPTION("Microchip PIC32 RNG Driver"); 152