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 TRNGMOD BIT(11) 24730d02e2SJoshua Henderson #define RNGSEED1 0x18 25730d02e2SJoshua Henderson #define RNGSEED2 0x1C 26730d02e2SJoshua Henderson #define RNGRCNT 0x20 27730d02e2SJoshua Henderson #define RCNT_MASK 0x7F 28730d02e2SJoshua Henderson 29730d02e2SJoshua Henderson struct pic32_rng { 30730d02e2SJoshua Henderson void __iomem *base; 31730d02e2SJoshua Henderson struct hwrng rng; 32730d02e2SJoshua Henderson }; 33730d02e2SJoshua Henderson 34730d02e2SJoshua Henderson /* 35730d02e2SJoshua Henderson * The TRNG can generate up to 24Mbps. This is a timeout that should be safe 36730d02e2SJoshua Henderson * enough given the instructions in the loop and that the TRNG may not always 37730d02e2SJoshua Henderson * be at maximum rate. 38730d02e2SJoshua Henderson */ 39730d02e2SJoshua Henderson #define RNG_TIMEOUT 500 40730d02e2SJoshua Henderson 41*ac0042faSMartin Kaiser static int pic32_rng_init(struct hwrng *rng) 42*ac0042faSMartin Kaiser { 43*ac0042faSMartin Kaiser struct pic32_rng *priv = container_of(rng, struct pic32_rng, rng); 44*ac0042faSMartin Kaiser 45*ac0042faSMartin Kaiser /* enable TRNG in enhanced mode */ 46*ac0042faSMartin Kaiser writel(TRNGEN | TRNGMOD, priv->base + RNGCON); 47*ac0042faSMartin Kaiser return 0; 48*ac0042faSMartin Kaiser } 49*ac0042faSMartin Kaiser 50730d02e2SJoshua Henderson static int pic32_rng_read(struct hwrng *rng, void *buf, size_t max, 51730d02e2SJoshua Henderson bool wait) 52730d02e2SJoshua Henderson { 53730d02e2SJoshua Henderson struct pic32_rng *priv = container_of(rng, struct pic32_rng, rng); 54730d02e2SJoshua Henderson u64 *data = buf; 55730d02e2SJoshua Henderson u32 t; 56730d02e2SJoshua Henderson unsigned int timeout = RNG_TIMEOUT; 57730d02e2SJoshua Henderson 58730d02e2SJoshua Henderson do { 59730d02e2SJoshua Henderson t = readl(priv->base + RNGRCNT) & RCNT_MASK; 60730d02e2SJoshua Henderson if (t == 64) { 61730d02e2SJoshua Henderson /* TRNG value comes through the seed registers */ 62730d02e2SJoshua Henderson *data = ((u64)readl(priv->base + RNGSEED2) << 32) + 63730d02e2SJoshua Henderson readl(priv->base + RNGSEED1); 64730d02e2SJoshua Henderson return 8; 65730d02e2SJoshua Henderson } 66730d02e2SJoshua Henderson } while (wait && --timeout); 67730d02e2SJoshua Henderson 68730d02e2SJoshua Henderson return -EIO; 69730d02e2SJoshua Henderson } 70730d02e2SJoshua Henderson 71*ac0042faSMartin Kaiser static void pic32_rng_cleanup(struct hwrng *rng) 72*ac0042faSMartin Kaiser { 73*ac0042faSMartin Kaiser struct pic32_rng *priv = container_of(rng, struct pic32_rng, rng); 74*ac0042faSMartin Kaiser 75*ac0042faSMartin Kaiser writel(0, priv->base + RNGCON); 76*ac0042faSMartin Kaiser } 77*ac0042faSMartin Kaiser 78730d02e2SJoshua Henderson static int pic32_rng_probe(struct platform_device *pdev) 79730d02e2SJoshua Henderson { 80730d02e2SJoshua Henderson struct pic32_rng *priv; 816755ad74SMartin Kaiser struct clk *clk; 82730d02e2SJoshua Henderson 83730d02e2SJoshua Henderson priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 84730d02e2SJoshua Henderson if (!priv) 85730d02e2SJoshua Henderson return -ENOMEM; 86730d02e2SJoshua Henderson 8764b7bf13SYueHaibing priv->base = devm_platform_ioremap_resource(pdev, 0); 88730d02e2SJoshua Henderson if (IS_ERR(priv->base)) 89730d02e2SJoshua Henderson return PTR_ERR(priv->base); 90730d02e2SJoshua Henderson 916755ad74SMartin Kaiser clk = devm_clk_get_enabled(&pdev->dev, NULL); 926755ad74SMartin Kaiser if (IS_ERR(clk)) 936755ad74SMartin Kaiser return PTR_ERR(clk); 94730d02e2SJoshua Henderson 95730d02e2SJoshua Henderson priv->rng.name = pdev->name; 96*ac0042faSMartin Kaiser priv->rng.init = pic32_rng_init; 97730d02e2SJoshua Henderson priv->rng.read = pic32_rng_read; 98*ac0042faSMartin Kaiser priv->rng.cleanup = pic32_rng_cleanup; 99730d02e2SJoshua Henderson 100*ac0042faSMartin Kaiser return devm_hwrng_register(&pdev->dev, &priv->rng); 101730d02e2SJoshua Henderson } 102730d02e2SJoshua Henderson 103e05231a5SHerbert Xu static const struct of_device_id pic32_rng_of_match[] __maybe_unused = { 104730d02e2SJoshua Henderson { .compatible = "microchip,pic32mzda-rng", }, 105730d02e2SJoshua Henderson { /* sentinel */ } 106730d02e2SJoshua Henderson }; 107730d02e2SJoshua Henderson MODULE_DEVICE_TABLE(of, pic32_rng_of_match); 108730d02e2SJoshua Henderson 109730d02e2SJoshua Henderson static struct platform_driver pic32_rng_driver = { 110730d02e2SJoshua Henderson .probe = pic32_rng_probe, 111730d02e2SJoshua Henderson .driver = { 112730d02e2SJoshua Henderson .name = "pic32-rng", 113730d02e2SJoshua Henderson .of_match_table = of_match_ptr(pic32_rng_of_match), 114730d02e2SJoshua Henderson }, 115730d02e2SJoshua Henderson }; 116730d02e2SJoshua Henderson 117730d02e2SJoshua Henderson module_platform_driver(pic32_rng_driver); 118730d02e2SJoshua Henderson 119730d02e2SJoshua Henderson MODULE_LICENSE("GPL"); 120730d02e2SJoshua Henderson MODULE_AUTHOR("Joshua Henderson <joshua.henderson@microchip.com>"); 121730d02e2SJoshua Henderson MODULE_DESCRIPTION("Microchip PIC32 RNG Driver"); 122