1bc85b25eSAlessandro Rubini /* 2bc85b25eSAlessandro Rubini * Nomadik RNG support 3bc85b25eSAlessandro Rubini * Copyright 2009 Alessandro Rubini 4bc85b25eSAlessandro Rubini * 5bc85b25eSAlessandro Rubini * This program is free software; you can redistribute it and/or modify 6bc85b25eSAlessandro Rubini * it under the terms of the GNU General Public License as published by 7bc85b25eSAlessandro Rubini * the Free Software Foundation; either version 2 of the License, or 8bc85b25eSAlessandro Rubini * (at your option) any later version. 9bc85b25eSAlessandro Rubini */ 10bc85b25eSAlessandro Rubini 11bc85b25eSAlessandro Rubini #include <linux/kernel.h> 12bc85b25eSAlessandro Rubini #include <linux/module.h> 13bc85b25eSAlessandro Rubini #include <linux/init.h> 14bc85b25eSAlessandro Rubini #include <linux/device.h> 15bc85b25eSAlessandro Rubini #include <linux/amba/bus.h> 16bc85b25eSAlessandro Rubini #include <linux/hw_random.h> 17bc85b25eSAlessandro Rubini #include <linux/io.h> 18bc85b25eSAlessandro Rubini 19bc85b25eSAlessandro Rubini static int nmk_rng_read(struct hwrng *rng, void *data, size_t max, bool wait) 20bc85b25eSAlessandro Rubini { 21bc85b25eSAlessandro Rubini void __iomem *base = (void __iomem *)rng->priv; 22bc85b25eSAlessandro Rubini 23bc85b25eSAlessandro Rubini /* 24bc85b25eSAlessandro Rubini * The register is 32 bits and gives 16 random bits (low half). 25bc85b25eSAlessandro Rubini * A subsequent read will delay the core for 400ns, so we just read 26bc85b25eSAlessandro Rubini * once and accept the very unlikely very small delay, even if wait==0. 27bc85b25eSAlessandro Rubini */ 28bc85b25eSAlessandro Rubini *(u16 *)data = __raw_readl(base + 8) & 0xffff; 29bc85b25eSAlessandro Rubini return 2; 30bc85b25eSAlessandro Rubini } 31bc85b25eSAlessandro Rubini 32bc85b25eSAlessandro Rubini /* we have at most one RNG per machine, granted */ 33bc85b25eSAlessandro Rubini static struct hwrng nmk_rng = { 34bc85b25eSAlessandro Rubini .name = "nomadik", 35bc85b25eSAlessandro Rubini .read = nmk_rng_read, 36bc85b25eSAlessandro Rubini }; 37bc85b25eSAlessandro Rubini 38bc85b25eSAlessandro Rubini static int nmk_rng_probe(struct amba_device *dev, struct amba_id *id) 39bc85b25eSAlessandro Rubini { 40bc85b25eSAlessandro Rubini void __iomem *base; 41bc85b25eSAlessandro Rubini int ret; 42bc85b25eSAlessandro Rubini 43bc85b25eSAlessandro Rubini ret = amba_request_regions(dev, dev->dev.init_name); 44bc85b25eSAlessandro Rubini if (ret) 45bc85b25eSAlessandro Rubini return ret; 46bc85b25eSAlessandro Rubini ret = -ENOMEM; 47bc85b25eSAlessandro Rubini base = ioremap(dev->res.start, resource_size(&dev->res)); 48bc85b25eSAlessandro Rubini if (!base) 49bc85b25eSAlessandro Rubini goto out_release; 50bc85b25eSAlessandro Rubini nmk_rng.priv = (unsigned long)base; 51bc85b25eSAlessandro Rubini ret = hwrng_register(&nmk_rng); 52bc85b25eSAlessandro Rubini if (ret) 53bc85b25eSAlessandro Rubini goto out_unmap; 54bc85b25eSAlessandro Rubini return 0; 55bc85b25eSAlessandro Rubini 56bc85b25eSAlessandro Rubini out_unmap: 57bc85b25eSAlessandro Rubini iounmap(base); 58bc85b25eSAlessandro Rubini out_release: 59bc85b25eSAlessandro Rubini amba_release_regions(dev); 60bc85b25eSAlessandro Rubini return ret; 61bc85b25eSAlessandro Rubini } 62bc85b25eSAlessandro Rubini 63bc85b25eSAlessandro Rubini static int nmk_rng_remove(struct amba_device *dev) 64bc85b25eSAlessandro Rubini { 65bc85b25eSAlessandro Rubini void __iomem *base = (void __iomem *)nmk_rng.priv; 66bc85b25eSAlessandro Rubini hwrng_unregister(&nmk_rng); 67bc85b25eSAlessandro Rubini iounmap(base); 68bc85b25eSAlessandro Rubini amba_release_regions(dev); 69bc85b25eSAlessandro Rubini return 0; 70bc85b25eSAlessandro Rubini } 71bc85b25eSAlessandro Rubini 72bc85b25eSAlessandro Rubini static struct amba_id nmk_rng_ids[] = { 73bc85b25eSAlessandro Rubini { 74bc85b25eSAlessandro Rubini .id = 0x000805e1, 75bc85b25eSAlessandro Rubini .mask = 0x000fffff, /* top bits are rev and cfg: accept all */ 76bc85b25eSAlessandro Rubini }, 77bc85b25eSAlessandro Rubini {0, 0}, 78bc85b25eSAlessandro Rubini }; 79bc85b25eSAlessandro Rubini 80bc85b25eSAlessandro Rubini static struct amba_driver nmk_rng_driver = { 81bc85b25eSAlessandro Rubini .drv = { 82bc85b25eSAlessandro Rubini .owner = THIS_MODULE, 83bc85b25eSAlessandro Rubini .name = "rng", 84bc85b25eSAlessandro Rubini }, 85bc85b25eSAlessandro Rubini .probe = nmk_rng_probe, 86bc85b25eSAlessandro Rubini .remove = nmk_rng_remove, 87bc85b25eSAlessandro Rubini .id_table = nmk_rng_ids, 88bc85b25eSAlessandro Rubini }; 89bc85b25eSAlessandro Rubini 90bc85b25eSAlessandro Rubini static int __init nmk_rng_init(void) 91bc85b25eSAlessandro Rubini { 92bc85b25eSAlessandro Rubini return amba_driver_register(&nmk_rng_driver); 93bc85b25eSAlessandro Rubini } 94bc85b25eSAlessandro Rubini 95bc85b25eSAlessandro Rubini static void __devexit nmk_rng_exit(void) 96bc85b25eSAlessandro Rubini { 97bc85b25eSAlessandro Rubini amba_driver_unregister(&nmk_rng_driver); 98bc85b25eSAlessandro Rubini } 99bc85b25eSAlessandro Rubini 100bc85b25eSAlessandro Rubini module_init(nmk_rng_init); 101bc85b25eSAlessandro Rubini module_exit(nmk_rng_exit); 102bc85b25eSAlessandro Rubini 103bc85b25eSAlessandro Rubini MODULE_LICENSE("GPL"); 104