Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.11 146 lines 3.2 kB view raw
1/* 2 * Generic PowerPC 44x RNG driver 3 * 4 * Copyright 2011 IBM Corporation 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License as published by the 8 * Free Software Foundation; version 2 of the License. 9 */ 10 11#include <linux/module.h> 12#include <linux/kernel.h> 13#include <linux/platform_device.h> 14#include <linux/hw_random.h> 15#include <linux/delay.h> 16#include <linux/of_platform.h> 17#include <asm/io.h> 18 19#define PPC4XX_TRNG_DEV_CTRL 0x60080 20 21#define PPC4XX_TRNGE 0x00020000 22#define PPC4XX_TRNG_CTRL 0x0008 23#define PPC4XX_TRNG_CTRL_DALM 0x20 24#define PPC4XX_TRNG_STAT 0x0004 25#define PPC4XX_TRNG_STAT_B 0x1 26#define PPC4XX_TRNG_DATA 0x0000 27 28#define MODULE_NAME "ppc4xx_rng" 29 30static int ppc4xx_rng_data_present(struct hwrng *rng, int wait) 31{ 32 void __iomem *rng_regs = (void __iomem *) rng->priv; 33 int busy, i, present = 0; 34 35 for (i = 0; i < 20; i++) { 36 busy = (in_le32(rng_regs + PPC4XX_TRNG_STAT) & PPC4XX_TRNG_STAT_B); 37 if (!busy || !wait) { 38 present = 1; 39 break; 40 } 41 udelay(10); 42 } 43 return present; 44} 45 46static int ppc4xx_rng_data_read(struct hwrng *rng, u32 *data) 47{ 48 void __iomem *rng_regs = (void __iomem *) rng->priv; 49 *data = in_le32(rng_regs + PPC4XX_TRNG_DATA); 50 return 4; 51} 52 53static int ppc4xx_rng_enable(int enable) 54{ 55 struct device_node *ctrl; 56 void __iomem *ctrl_reg; 57 int err = 0; 58 u32 val; 59 60 /* Find the main crypto device node and map it to turn the TRNG on */ 61 ctrl = of_find_compatible_node(NULL, NULL, "amcc,ppc4xx-crypto"); 62 if (!ctrl) 63 return -ENODEV; 64 65 ctrl_reg = of_iomap(ctrl, 0); 66 if (!ctrl_reg) { 67 err = -ENODEV; 68 goto out; 69 } 70 71 val = in_le32(ctrl_reg + PPC4XX_TRNG_DEV_CTRL); 72 73 if (enable) 74 val |= PPC4XX_TRNGE; 75 else 76 val = val & ~PPC4XX_TRNGE; 77 78 out_le32(ctrl_reg + PPC4XX_TRNG_DEV_CTRL, val); 79 iounmap(ctrl_reg); 80 81out: 82 of_node_put(ctrl); 83 84 return err; 85} 86 87static struct hwrng ppc4xx_rng = { 88 .name = MODULE_NAME, 89 .data_present = ppc4xx_rng_data_present, 90 .data_read = ppc4xx_rng_data_read, 91}; 92 93static int ppc4xx_rng_probe(struct platform_device *dev) 94{ 95 void __iomem *rng_regs; 96 int err = 0; 97 98 rng_regs = of_iomap(dev->dev.of_node, 0); 99 if (!rng_regs) 100 return -ENODEV; 101 102 err = ppc4xx_rng_enable(1); 103 if (err) 104 return err; 105 106 out_le32(rng_regs + PPC4XX_TRNG_CTRL, PPC4XX_TRNG_CTRL_DALM); 107 ppc4xx_rng.priv = (unsigned long) rng_regs; 108 109 err = hwrng_register(&ppc4xx_rng); 110 111 return err; 112} 113 114static int ppc4xx_rng_remove(struct platform_device *dev) 115{ 116 void __iomem *rng_regs = (void __iomem *) ppc4xx_rng.priv; 117 118 hwrng_unregister(&ppc4xx_rng); 119 ppc4xx_rng_enable(0); 120 iounmap(rng_regs); 121 122 return 0; 123} 124 125static struct of_device_id ppc4xx_rng_match[] = { 126 { .compatible = "ppc4xx-rng", }, 127 { .compatible = "amcc,ppc460ex-rng", }, 128 { .compatible = "amcc,ppc440epx-rng", }, 129 {}, 130}; 131 132static struct platform_driver ppc4xx_rng_driver = { 133 .driver = { 134 .name = MODULE_NAME, 135 .owner = THIS_MODULE, 136 .of_match_table = ppc4xx_rng_match, 137 }, 138 .probe = ppc4xx_rng_probe, 139 .remove = ppc4xx_rng_remove, 140}; 141 142module_platform_driver(ppc4xx_rng_driver); 143 144MODULE_LICENSE("GPL"); 145MODULE_AUTHOR("Josh Boyer <jwboyer@linux.vnet.ibm.com>"); 146MODULE_DESCRIPTION("HW RNG driver for PPC 4xx processors");