1 /* 2 * RNG driver for Freescale RNGC 3 * 4 * Copyright (C) 2008-2012 Freescale Semiconductor, Inc. 5 * Copyright (C) 2017 Martin Kaiser <martin@kaiser.cx> 6 * 7 * The code contained herein is licensed under the GNU General Public 8 * License. You may obtain a copy of the GNU General Public License 9 * Version 2 or later at the following locations: 10 * 11 * http://www.opensource.org/licenses/gpl-license.html 12 * http://www.gnu.org/copyleft/gpl.html 13 */ 14 15 #include <linux/module.h> 16 #include <linux/init.h> 17 #include <linux/kernel.h> 18 #include <linux/clk.h> 19 #include <linux/err.h> 20 #include <linux/platform_device.h> 21 #include <linux/interrupt.h> 22 #include <linux/hw_random.h> 23 #include <linux/completion.h> 24 #include <linux/io.h> 25 26 #define RNGC_COMMAND 0x0004 27 #define RNGC_CONTROL 0x0008 28 #define RNGC_STATUS 0x000C 29 #define RNGC_ERROR 0x0010 30 #define RNGC_FIFO 0x0014 31 32 #define RNGC_CMD_CLR_ERR 0x00000020 33 #define RNGC_CMD_CLR_INT 0x00000010 34 #define RNGC_CMD_SEED 0x00000002 35 #define RNGC_CMD_SELF_TEST 0x00000001 36 37 #define RNGC_CTRL_MASK_ERROR 0x00000040 38 #define RNGC_CTRL_MASK_DONE 0x00000020 39 40 #define RNGC_STATUS_ERROR 0x00010000 41 #define RNGC_STATUS_FIFO_LEVEL_MASK 0x00000f00 42 #define RNGC_STATUS_FIFO_LEVEL_SHIFT 8 43 #define RNGC_STATUS_SEED_DONE 0x00000020 44 #define RNGC_STATUS_ST_DONE 0x00000010 45 46 #define RNGC_ERROR_STATUS_STAT_ERR 0x00000008 47 48 #define RNGC_TIMEOUT 3000 /* 3 sec */ 49 50 51 static bool self_test = true; 52 module_param(self_test, bool, 0); 53 54 struct imx_rngc { 55 struct device *dev; 56 struct clk *clk; 57 void __iomem *base; 58 struct hwrng rng; 59 struct completion rng_op_done; 60 /* 61 * err_reg is written only by the irq handler and read only 62 * when interrupts are masked, we need no spinlock 63 */ 64 u32 err_reg; 65 }; 66 67 68 static inline void imx_rngc_irq_mask_clear(struct imx_rngc *rngc) 69 { 70 u32 ctrl, cmd; 71 72 /* mask interrupts */ 73 ctrl = readl(rngc->base + RNGC_CONTROL); 74 ctrl |= RNGC_CTRL_MASK_DONE | RNGC_CTRL_MASK_ERROR; 75 writel(ctrl, rngc->base + RNGC_CONTROL); 76 77 /* 78 * CLR_INT clears the interrupt only if there's no error 79 * CLR_ERR clear the interrupt and the error register if there 80 * is an error 81 */ 82 cmd = readl(rngc->base + RNGC_COMMAND); 83 cmd |= RNGC_CMD_CLR_INT | RNGC_CMD_CLR_ERR; 84 writel(cmd, rngc->base + RNGC_COMMAND); 85 } 86 87 static inline void imx_rngc_irq_unmask(struct imx_rngc *rngc) 88 { 89 u32 ctrl; 90 91 ctrl = readl(rngc->base + RNGC_CONTROL); 92 ctrl &= ~(RNGC_CTRL_MASK_DONE | RNGC_CTRL_MASK_ERROR); 93 writel(ctrl, rngc->base + RNGC_CONTROL); 94 } 95 96 static int imx_rngc_self_test(struct imx_rngc *rngc) 97 { 98 u32 cmd; 99 int ret; 100 101 imx_rngc_irq_unmask(rngc); 102 103 /* run self test */ 104 cmd = readl(rngc->base + RNGC_COMMAND); 105 writel(cmd | RNGC_CMD_SELF_TEST, rngc->base + RNGC_COMMAND); 106 107 ret = wait_for_completion_timeout(&rngc->rng_op_done, RNGC_TIMEOUT); 108 if (!ret) { 109 imx_rngc_irq_mask_clear(rngc); 110 return -ETIMEDOUT; 111 } 112 113 if (rngc->err_reg != 0) 114 return -EIO; 115 116 return 0; 117 } 118 119 static int imx_rngc_read(struct hwrng *rng, void *data, size_t max, bool wait) 120 { 121 struct imx_rngc *rngc = container_of(rng, struct imx_rngc, rng); 122 unsigned int status; 123 unsigned int level; 124 int retval = 0; 125 126 while (max >= sizeof(u32)) { 127 status = readl(rngc->base + RNGC_STATUS); 128 129 /* is there some error while reading this random number? */ 130 if (status & RNGC_STATUS_ERROR) 131 break; 132 133 /* how many random numbers are in FIFO? [0-16] */ 134 level = (status & RNGC_STATUS_FIFO_LEVEL_MASK) >> 135 RNGC_STATUS_FIFO_LEVEL_SHIFT; 136 137 if (level) { 138 /* retrieve a random number from FIFO */ 139 *(u32 *)data = readl(rngc->base + RNGC_FIFO); 140 141 retval += sizeof(u32); 142 data += sizeof(u32); 143 max -= sizeof(u32); 144 } 145 } 146 147 return retval ? retval : -EIO; 148 } 149 150 static irqreturn_t imx_rngc_irq(int irq, void *priv) 151 { 152 struct imx_rngc *rngc = (struct imx_rngc *)priv; 153 u32 status; 154 155 /* 156 * clearing the interrupt will also clear the error register 157 * read error and status before clearing 158 */ 159 status = readl(rngc->base + RNGC_STATUS); 160 rngc->err_reg = readl(rngc->base + RNGC_ERROR); 161 162 imx_rngc_irq_mask_clear(rngc); 163 164 if (status & (RNGC_STATUS_SEED_DONE | RNGC_STATUS_ST_DONE)) 165 complete(&rngc->rng_op_done); 166 167 return IRQ_HANDLED; 168 } 169 170 static int imx_rngc_init(struct hwrng *rng) 171 { 172 struct imx_rngc *rngc = container_of(rng, struct imx_rngc, rng); 173 u32 cmd; 174 int ret; 175 176 /* clear error */ 177 cmd = readl(rngc->base + RNGC_COMMAND); 178 writel(cmd | RNGC_CMD_CLR_ERR, rngc->base + RNGC_COMMAND); 179 180 /* create seed, repeat while there is some statistical error */ 181 do { 182 imx_rngc_irq_unmask(rngc); 183 184 /* seed creation */ 185 cmd = readl(rngc->base + RNGC_COMMAND); 186 writel(cmd | RNGC_CMD_SEED, rngc->base + RNGC_COMMAND); 187 188 ret = wait_for_completion_timeout(&rngc->rng_op_done, 189 RNGC_TIMEOUT); 190 191 if (!ret) { 192 imx_rngc_irq_mask_clear(rngc); 193 return -ETIMEDOUT; 194 } 195 196 } while (rngc->err_reg == RNGC_ERROR_STATUS_STAT_ERR); 197 198 return rngc->err_reg ? -EIO : 0; 199 } 200 201 static int imx_rngc_probe(struct platform_device *pdev) 202 { 203 struct imx_rngc *rngc; 204 struct resource *res; 205 int ret; 206 int irq; 207 208 rngc = devm_kzalloc(&pdev->dev, sizeof(*rngc), GFP_KERNEL); 209 if (!rngc) 210 return -ENOMEM; 211 212 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 213 rngc->base = devm_ioremap_resource(&pdev->dev, res); 214 if (IS_ERR(rngc->base)) 215 return PTR_ERR(rngc->base); 216 217 rngc->clk = devm_clk_get(&pdev->dev, NULL); 218 if (IS_ERR(rngc->clk)) { 219 dev_err(&pdev->dev, "Can not get rng_clk\n"); 220 return PTR_ERR(rngc->clk); 221 } 222 223 irq = platform_get_irq(pdev, 0); 224 if (irq <= 0) { 225 dev_err(&pdev->dev, "Couldn't get irq %d\n", irq); 226 return irq; 227 } 228 229 ret = clk_prepare_enable(rngc->clk); 230 if (ret) 231 return ret; 232 233 ret = devm_request_irq(&pdev->dev, 234 irq, imx_rngc_irq, 0, pdev->name, (void *)rngc); 235 if (ret) { 236 dev_err(rngc->dev, "Can't get interrupt working.\n"); 237 goto err; 238 } 239 240 init_completion(&rngc->rng_op_done); 241 242 rngc->rng.name = pdev->name; 243 rngc->rng.init = imx_rngc_init; 244 rngc->rng.read = imx_rngc_read; 245 246 rngc->dev = &pdev->dev; 247 platform_set_drvdata(pdev, rngc); 248 249 imx_rngc_irq_mask_clear(rngc); 250 251 if (self_test) { 252 ret = imx_rngc_self_test(rngc); 253 if (ret) { 254 dev_err(rngc->dev, "FSL RNGC self test failed.\n"); 255 goto err; 256 } 257 } 258 259 ret = hwrng_register(&rngc->rng); 260 if (ret) { 261 dev_err(&pdev->dev, "FSL RNGC registering failed (%d)\n", ret); 262 goto err; 263 } 264 265 dev_info(&pdev->dev, "Freescale RNGC registered.\n"); 266 return 0; 267 268 err: 269 clk_disable_unprepare(rngc->clk); 270 271 return ret; 272 } 273 274 static int __exit imx_rngc_remove(struct platform_device *pdev) 275 { 276 struct imx_rngc *rngc = platform_get_drvdata(pdev); 277 278 hwrng_unregister(&rngc->rng); 279 280 clk_disable_unprepare(rngc->clk); 281 282 return 0; 283 } 284 285 static int __maybe_unused imx_rngc_suspend(struct device *dev) 286 { 287 struct imx_rngc *rngc = dev_get_drvdata(dev); 288 289 clk_disable_unprepare(rngc->clk); 290 291 return 0; 292 } 293 294 static int __maybe_unused imx_rngc_resume(struct device *dev) 295 { 296 struct imx_rngc *rngc = dev_get_drvdata(dev); 297 298 clk_prepare_enable(rngc->clk); 299 300 return 0; 301 } 302 303 SIMPLE_DEV_PM_OPS(imx_rngc_pm_ops, imx_rngc_suspend, imx_rngc_resume); 304 305 static const struct of_device_id imx_rngc_dt_ids[] = { 306 { .compatible = "fsl,imx25-rngb", .data = NULL, }, 307 { /* sentinel */ } 308 }; 309 MODULE_DEVICE_TABLE(of, imx_rngc_dt_ids); 310 311 static struct platform_driver imx_rngc_driver = { 312 .driver = { 313 .name = "imx_rngc", 314 .pm = &imx_rngc_pm_ops, 315 .of_match_table = imx_rngc_dt_ids, 316 }, 317 .remove = __exit_p(imx_rngc_remove), 318 }; 319 320 module_platform_driver_probe(imx_rngc_driver, imx_rngc_probe); 321 322 MODULE_AUTHOR("Freescale Semiconductor, Inc."); 323 MODULE_DESCRIPTION("H/W RNGC driver for i.MX"); 324 MODULE_LICENSE("GPL"); 325