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/clk.h> 20 #include <linux/delay.h> 21 #include <linux/hw_random.h> 22 #include <linux/io.h> 23 #include <linux/module.h> 24 #include <linux/of.h> 25 #include <linux/platform_device.h> 26 27 /* RNGA Registers */ 28 #define RNGA_CONTROL 0x00 29 #define RNGA_STATUS 0x04 30 #define RNGA_ENTROPY 0x08 31 #define RNGA_OUTPUT_FIFO 0x0c 32 #define RNGA_MODE 0x10 33 #define RNGA_VERIFICATION_CONTROL 0x14 34 #define RNGA_OSC_CONTROL_COUNTER 0x18 35 #define RNGA_OSC1_COUNTER 0x1c 36 #define RNGA_OSC2_COUNTER 0x20 37 #define RNGA_OSC_COUNTER_STATUS 0x24 38 39 /* RNGA Registers Range */ 40 #define RNG_ADDR_RANGE 0x28 41 42 /* RNGA Control Register */ 43 #define RNGA_CONTROL_SLEEP 0x00000010 44 #define RNGA_CONTROL_CLEAR_INT 0x00000008 45 #define RNGA_CONTROL_MASK_INTS 0x00000004 46 #define RNGA_CONTROL_HIGH_ASSURANCE 0x00000002 47 #define RNGA_CONTROL_GO 0x00000001 48 49 #define RNGA_STATUS_LEVEL_MASK 0x0000ff00 50 51 /* RNGA Status Register */ 52 #define RNGA_STATUS_OSC_DEAD 0x80000000 53 #define RNGA_STATUS_SLEEP 0x00000010 54 #define RNGA_STATUS_ERROR_INT 0x00000008 55 #define RNGA_STATUS_FIFO_UNDERFLOW 0x00000004 56 #define RNGA_STATUS_LAST_READ_STATUS 0x00000002 57 #define RNGA_STATUS_SECURITY_VIOLATION 0x00000001 58 59 struct mxc_rng { 60 struct device *dev; 61 struct hwrng rng; 62 void __iomem *mem; 63 struct clk *clk; 64 }; 65 66 static int mxc_rnga_data_present(struct hwrng *rng, int wait) 67 { 68 int i; 69 struct mxc_rng *mxc_rng = container_of(rng, struct mxc_rng, rng); 70 71 for (i = 0; i < 20; i++) { 72 /* how many random numbers are in FIFO? [0-16] */ 73 int level = (__raw_readl(mxc_rng->mem + RNGA_STATUS) & 74 RNGA_STATUS_LEVEL_MASK) >> 8; 75 if (level || !wait) 76 return !!level; 77 udelay(10); 78 } 79 return 0; 80 } 81 82 static int mxc_rnga_data_read(struct hwrng *rng, u32 * data) 83 { 84 int err; 85 u32 ctrl; 86 struct mxc_rng *mxc_rng = container_of(rng, struct mxc_rng, rng); 87 88 /* retrieve a random number from FIFO */ 89 *data = __raw_readl(mxc_rng->mem + RNGA_OUTPUT_FIFO); 90 91 /* some error while reading this random number? */ 92 err = __raw_readl(mxc_rng->mem + RNGA_STATUS) & RNGA_STATUS_ERROR_INT; 93 94 /* if error: clear error interrupt, but doesn't return random number */ 95 if (err) { 96 dev_dbg(mxc_rng->dev, "Error while reading random number!\n"); 97 ctrl = __raw_readl(mxc_rng->mem + RNGA_CONTROL); 98 __raw_writel(ctrl | RNGA_CONTROL_CLEAR_INT, 99 mxc_rng->mem + RNGA_CONTROL); 100 return 0; 101 } else 102 return 4; 103 } 104 105 static int mxc_rnga_init(struct hwrng *rng) 106 { 107 u32 ctrl, osc; 108 struct mxc_rng *mxc_rng = container_of(rng, struct mxc_rng, rng); 109 110 /* wake up */ 111 ctrl = __raw_readl(mxc_rng->mem + RNGA_CONTROL); 112 __raw_writel(ctrl & ~RNGA_CONTROL_SLEEP, mxc_rng->mem + RNGA_CONTROL); 113 114 /* verify if oscillator is working */ 115 osc = __raw_readl(mxc_rng->mem + RNGA_STATUS); 116 if (osc & RNGA_STATUS_OSC_DEAD) { 117 dev_err(mxc_rng->dev, "RNGA Oscillator is dead!\n"); 118 return -ENODEV; 119 } 120 121 /* go running */ 122 ctrl = __raw_readl(mxc_rng->mem + RNGA_CONTROL); 123 __raw_writel(ctrl | RNGA_CONTROL_GO, mxc_rng->mem + RNGA_CONTROL); 124 125 return 0; 126 } 127 128 static void mxc_rnga_cleanup(struct hwrng *rng) 129 { 130 u32 ctrl; 131 struct mxc_rng *mxc_rng = container_of(rng, struct mxc_rng, rng); 132 133 ctrl = __raw_readl(mxc_rng->mem + RNGA_CONTROL); 134 135 /* stop rnga */ 136 __raw_writel(ctrl & ~RNGA_CONTROL_GO, mxc_rng->mem + RNGA_CONTROL); 137 } 138 139 static int __init mxc_rnga_probe(struct platform_device *pdev) 140 { 141 int err; 142 struct resource *res; 143 struct mxc_rng *mxc_rng; 144 145 mxc_rng = devm_kzalloc(&pdev->dev, sizeof(*mxc_rng), GFP_KERNEL); 146 if (!mxc_rng) 147 return -ENOMEM; 148 149 mxc_rng->dev = &pdev->dev; 150 mxc_rng->rng.name = "mxc-rnga"; 151 mxc_rng->rng.init = mxc_rnga_init; 152 mxc_rng->rng.cleanup = mxc_rnga_cleanup, 153 mxc_rng->rng.data_present = mxc_rnga_data_present, 154 mxc_rng->rng.data_read = mxc_rnga_data_read, 155 156 mxc_rng->clk = devm_clk_get(&pdev->dev, NULL); 157 if (IS_ERR(mxc_rng->clk)) { 158 dev_err(&pdev->dev, "Could not get rng_clk!\n"); 159 return PTR_ERR(mxc_rng->clk); 160 } 161 162 err = clk_prepare_enable(mxc_rng->clk); 163 if (err) 164 return err; 165 166 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 167 mxc_rng->mem = devm_ioremap_resource(&pdev->dev, res); 168 if (IS_ERR(mxc_rng->mem)) { 169 err = PTR_ERR(mxc_rng->mem); 170 goto err_ioremap; 171 } 172 173 err = hwrng_register(&mxc_rng->rng); 174 if (err) { 175 dev_err(&pdev->dev, "MXC RNGA registering failed (%d)\n", err); 176 goto err_ioremap; 177 } 178 179 return 0; 180 181 err_ioremap: 182 clk_disable_unprepare(mxc_rng->clk); 183 return err; 184 } 185 186 static int __exit mxc_rnga_remove(struct platform_device *pdev) 187 { 188 struct mxc_rng *mxc_rng = platform_get_drvdata(pdev); 189 190 hwrng_unregister(&mxc_rng->rng); 191 192 clk_disable_unprepare(mxc_rng->clk); 193 194 return 0; 195 } 196 197 static const struct of_device_id mxc_rnga_of_match[] = { 198 { .compatible = "fsl,imx21-rnga", }, 199 { .compatible = "fsl,imx31-rnga", }, 200 { /* sentinel */ }, 201 }; 202 MODULE_DEVICE_TABLE(of, mxc_rnga_of_match); 203 204 static struct platform_driver mxc_rnga_driver = { 205 .driver = { 206 .name = "mxc_rnga", 207 .of_match_table = mxc_rnga_of_match, 208 }, 209 .remove = __exit_p(mxc_rnga_remove), 210 }; 211 212 module_platform_driver_probe(mxc_rnga_driver, mxc_rnga_probe); 213 214 MODULE_AUTHOR("Freescale Semiconductor, Inc."); 215 MODULE_DESCRIPTION("H/W RNGA driver for i.MX"); 216 MODULE_LICENSE("GPL"); 217