1 /* 2 * RNG driver for Freescale RNGA 3 * 4 * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. 5 * Author: Alan Carvalho de Assis <acassis@gmail.com> 6 */ 7 8 /* 9 * The code contained herein is licensed under the GNU General Public 10 * License. You may obtain a copy of the GNU General Public License 11 * Version 2 or later at the following locations: 12 * 13 * http://www.opensource.org/licenses/gpl-license.html 14 * http://www.gnu.org/copyleft/gpl.html 15 * 16 * This driver is based on other RNG drivers. 17 */ 18 19 #include <linux/module.h> 20 #include <linux/init.h> 21 #include <linux/kernel.h> 22 #include <linux/clk.h> 23 #include <linux/err.h> 24 #include <linux/ioport.h> 25 #include <linux/platform_device.h> 26 #include <linux/hw_random.h> 27 #include <linux/delay.h> 28 #include <linux/io.h> 29 30 /* RNGA Registers */ 31 #define RNGA_CONTROL 0x00 32 #define RNGA_STATUS 0x04 33 #define RNGA_ENTROPY 0x08 34 #define RNGA_OUTPUT_FIFO 0x0c 35 #define RNGA_MODE 0x10 36 #define RNGA_VERIFICATION_CONTROL 0x14 37 #define RNGA_OSC_CONTROL_COUNTER 0x18 38 #define RNGA_OSC1_COUNTER 0x1c 39 #define RNGA_OSC2_COUNTER 0x20 40 #define RNGA_OSC_COUNTER_STATUS 0x24 41 42 /* RNGA Registers Range */ 43 #define RNG_ADDR_RANGE 0x28 44 45 /* RNGA Control Register */ 46 #define RNGA_CONTROL_SLEEP 0x00000010 47 #define RNGA_CONTROL_CLEAR_INT 0x00000008 48 #define RNGA_CONTROL_MASK_INTS 0x00000004 49 #define RNGA_CONTROL_HIGH_ASSURANCE 0x00000002 50 #define RNGA_CONTROL_GO 0x00000001 51 52 #define RNGA_STATUS_LEVEL_MASK 0x0000ff00 53 54 /* RNGA Status Register */ 55 #define RNGA_STATUS_OSC_DEAD 0x80000000 56 #define RNGA_STATUS_SLEEP 0x00000010 57 #define RNGA_STATUS_ERROR_INT 0x00000008 58 #define RNGA_STATUS_FIFO_UNDERFLOW 0x00000004 59 #define RNGA_STATUS_LAST_READ_STATUS 0x00000002 60 #define RNGA_STATUS_SECURITY_VIOLATION 0x00000001 61 62 static struct platform_device *rng_dev; 63 64 static int mxc_rnga_data_present(struct hwrng *rng, int wait) 65 { 66 void __iomem *rng_base = (void __iomem *)rng->priv; 67 int i; 68 69 for (i = 0; i < 20; i++) { 70 /* how many random numbers are in FIFO? [0-16] */ 71 int level = (__raw_readl(rng_base + RNGA_STATUS) & 72 RNGA_STATUS_LEVEL_MASK) >> 8; 73 if (level || !wait) 74 return !!level; 75 udelay(10); 76 } 77 return 0; 78 } 79 80 static int mxc_rnga_data_read(struct hwrng *rng, u32 * data) 81 { 82 int err; 83 u32 ctrl; 84 void __iomem *rng_base = (void __iomem *)rng->priv; 85 86 /* retrieve a random number from FIFO */ 87 *data = __raw_readl(rng_base + RNGA_OUTPUT_FIFO); 88 89 /* some error while reading this random number? */ 90 err = __raw_readl(rng_base + RNGA_STATUS) & RNGA_STATUS_ERROR_INT; 91 92 /* if error: clear error interrupt, but doesn't return random number */ 93 if (err) { 94 dev_dbg(&rng_dev->dev, "Error while reading random number!\n"); 95 ctrl = __raw_readl(rng_base + RNGA_CONTROL); 96 __raw_writel(ctrl | RNGA_CONTROL_CLEAR_INT, 97 rng_base + RNGA_CONTROL); 98 return 0; 99 } else 100 return 4; 101 } 102 103 static int mxc_rnga_init(struct hwrng *rng) 104 { 105 u32 ctrl, osc; 106 void __iomem *rng_base = (void __iomem *)rng->priv; 107 108 /* wake up */ 109 ctrl = __raw_readl(rng_base + RNGA_CONTROL); 110 __raw_writel(ctrl & ~RNGA_CONTROL_SLEEP, rng_base + RNGA_CONTROL); 111 112 /* verify if oscillator is working */ 113 osc = __raw_readl(rng_base + RNGA_STATUS); 114 if (osc & RNGA_STATUS_OSC_DEAD) { 115 dev_err(&rng_dev->dev, "RNGA Oscillator is dead!\n"); 116 return -ENODEV; 117 } 118 119 /* go running */ 120 ctrl = __raw_readl(rng_base + RNGA_CONTROL); 121 __raw_writel(ctrl | RNGA_CONTROL_GO, rng_base + RNGA_CONTROL); 122 123 return 0; 124 } 125 126 static void mxc_rnga_cleanup(struct hwrng *rng) 127 { 128 u32 ctrl; 129 void __iomem *rng_base = (void __iomem *)rng->priv; 130 131 ctrl = __raw_readl(rng_base + RNGA_CONTROL); 132 133 /* stop rnga */ 134 __raw_writel(ctrl & ~RNGA_CONTROL_GO, rng_base + RNGA_CONTROL); 135 } 136 137 static struct hwrng mxc_rnga = { 138 .name = "mxc-rnga", 139 .init = mxc_rnga_init, 140 .cleanup = mxc_rnga_cleanup, 141 .data_present = mxc_rnga_data_present, 142 .data_read = mxc_rnga_data_read 143 }; 144 145 static int __init mxc_rnga_probe(struct platform_device *pdev) 146 { 147 int err = -ENODEV; 148 struct clk *clk; 149 struct resource *res, *mem; 150 void __iomem *rng_base = NULL; 151 152 if (rng_dev) 153 return -EBUSY; 154 155 clk = clk_get(&pdev->dev, "rng"); 156 if (IS_ERR(clk)) { 157 dev_err(&pdev->dev, "Could not get rng_clk!\n"); 158 err = PTR_ERR(clk); 159 goto out; 160 } 161 162 clk_enable(clk); 163 164 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 165 if (!res) { 166 err = -ENOENT; 167 goto err_region; 168 } 169 170 mem = request_mem_region(res->start, resource_size(res), pdev->name); 171 if (mem == NULL) { 172 err = -EBUSY; 173 goto err_region; 174 } 175 176 rng_base = ioremap(res->start, resource_size(res)); 177 if (!rng_base) { 178 err = -ENOMEM; 179 goto err_ioremap; 180 } 181 182 mxc_rnga.priv = (unsigned long)rng_base; 183 184 err = hwrng_register(&mxc_rnga); 185 if (err) { 186 dev_err(&pdev->dev, "MXC RNGA registering failed (%d)\n", err); 187 goto err_register; 188 } 189 190 rng_dev = pdev; 191 192 dev_info(&pdev->dev, "MXC RNGA Registered.\n"); 193 194 return 0; 195 196 err_register: 197 iounmap(rng_base); 198 rng_base = NULL; 199 200 err_ioremap: 201 release_mem_region(res->start, resource_size(res)); 202 203 err_region: 204 clk_disable(clk); 205 clk_put(clk); 206 207 out: 208 return err; 209 } 210 211 static int __exit mxc_rnga_remove(struct platform_device *pdev) 212 { 213 struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 214 void __iomem *rng_base = (void __iomem *)mxc_rnga.priv; 215 struct clk *clk = clk_get(&pdev->dev, "rng"); 216 217 hwrng_unregister(&mxc_rnga); 218 219 iounmap(rng_base); 220 221 release_mem_region(res->start, resource_size(res)); 222 223 clk_disable(clk); 224 clk_put(clk); 225 226 return 0; 227 } 228 229 static struct platform_driver mxc_rnga_driver = { 230 .driver = { 231 .name = "mxc_rnga", 232 .owner = THIS_MODULE, 233 }, 234 .remove = __exit_p(mxc_rnga_remove), 235 }; 236 237 static int __init mod_init(void) 238 { 239 return platform_driver_probe(&mxc_rnga_driver, mxc_rnga_probe); 240 } 241 242 static void __exit mod_exit(void) 243 { 244 platform_driver_unregister(&mxc_rnga_driver); 245 } 246 247 module_init(mod_init); 248 module_exit(mod_exit); 249 250 MODULE_AUTHOR("Freescale Semiconductor, Inc."); 251 MODULE_DESCRIPTION("H/W RNGA driver for i.MX"); 252 MODULE_LICENSE("GPL"); 253