1 /* 2 * RNG driver for AMD Geode RNGs 3 * 4 * Copyright 2005 (c) MontaVista Software, Inc. 5 * 6 * with the majority of the code coming from: 7 * 8 * Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG) 9 * (c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com> 10 * 11 * derived from 12 * 13 * Hardware driver for the AMD 768 Random Number Generator (RNG) 14 * (c) Copyright 2001 Red Hat Inc 15 * 16 * derived from 17 * 18 * Hardware driver for Intel i810 Random Number Generator (RNG) 19 * Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com> 20 * Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com> 21 * 22 * This file is licensed under the terms of the GNU General Public 23 * License version 2. This program is licensed "as is" without any 24 * warranty of any kind, whether express or implied. 25 */ 26 27 #include <linux/delay.h> 28 #include <linux/hw_random.h> 29 #include <linux/io.h> 30 #include <linux/kernel.h> 31 #include <linux/module.h> 32 #include <linux/pci.h> 33 34 #define GEODE_RNG_DATA_REG 0x50 35 #define GEODE_RNG_STATUS_REG 0x54 36 37 /* 38 * Data for PCI driver interface 39 * 40 * This data only exists for exporting the supported 41 * PCI ids via MODULE_DEVICE_TABLE. We do not actually 42 * register a pci_driver, because someone else might one day 43 * want to register another driver on the same PCI id. 44 */ 45 static const struct pci_device_id pci_tbl[] = { 46 { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_LX_AES), 0, }, 47 { 0, }, /* terminate list */ 48 }; 49 MODULE_DEVICE_TABLE(pci, pci_tbl); 50 51 52 static int geode_rng_data_read(struct hwrng *rng, u32 *data) 53 { 54 void __iomem *mem = (void __iomem *)rng->priv; 55 56 *data = readl(mem + GEODE_RNG_DATA_REG); 57 58 return 4; 59 } 60 61 static int geode_rng_data_present(struct hwrng *rng, int wait) 62 { 63 void __iomem *mem = (void __iomem *)rng->priv; 64 int data, i; 65 66 for (i = 0; i < 20; i++) { 67 data = !!(readl(mem + GEODE_RNG_STATUS_REG)); 68 if (data || !wait) 69 break; 70 udelay(10); 71 } 72 return data; 73 } 74 75 76 static struct hwrng geode_rng = { 77 .name = "geode", 78 .data_present = geode_rng_data_present, 79 .data_read = geode_rng_data_read, 80 }; 81 82 83 static int __init mod_init(void) 84 { 85 struct pci_dev *pdev = NULL; 86 const struct pci_device_id *ent; 87 void __iomem *mem; 88 unsigned long rng_base; 89 90 for_each_pci_dev(pdev) { 91 ent = pci_match_id(pci_tbl, pdev); 92 if (ent) { 93 rng_base = pci_resource_start(pdev, 0); 94 if (rng_base == 0) 95 return -ENODEV; 96 97 mem = devm_ioremap(&pdev->dev, rng_base, 0x58); 98 if (!mem) 99 return -ENOMEM; 100 geode_rng.priv = (unsigned long)mem; 101 102 pr_info("AMD Geode RNG detected\n"); 103 return devm_hwrng_register(&pdev->dev, &geode_rng); 104 } 105 } 106 107 /* Device not found. */ 108 return -ENODEV; 109 } 110 111 static void __exit mod_exit(void) 112 { 113 } 114 115 module_init(mod_init); 116 module_exit(mod_exit); 117 118 MODULE_DESCRIPTION("H/W RNG driver for AMD Geode LX CPUs"); 119 MODULE_LICENSE("GPL"); 120