1 /* 2 * exynos-rng.c - Random Number Generator driver for the Exynos 3 * 4 * Copyright (c) 2017 Krzysztof Kozlowski <krzk@kernel.org> 5 * 6 * Loosely based on old driver from drivers/char/hw_random/exynos-rng.c: 7 * Copyright (C) 2012 Samsung Electronics 8 * Jonghwa Lee <jonghwa3.lee@samsung.com> 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 */ 19 20 #include <linux/clk.h> 21 #include <linux/crypto.h> 22 #include <linux/err.h> 23 #include <linux/io.h> 24 #include <linux/module.h> 25 #include <linux/platform_device.h> 26 27 #include <crypto/internal/rng.h> 28 29 #define EXYNOS_RNG_CONTROL 0x0 30 #define EXYNOS_RNG_STATUS 0x10 31 #define EXYNOS_RNG_SEED_BASE 0x140 32 #define EXYNOS_RNG_SEED(n) (EXYNOS_RNG_SEED_BASE + (n * 0x4)) 33 #define EXYNOS_RNG_OUT_BASE 0x160 34 #define EXYNOS_RNG_OUT(n) (EXYNOS_RNG_OUT_BASE + (n * 0x4)) 35 36 /* EXYNOS_RNG_CONTROL bit fields */ 37 #define EXYNOS_RNG_CONTROL_START 0x18 38 /* EXYNOS_RNG_STATUS bit fields */ 39 #define EXYNOS_RNG_STATUS_SEED_SETTING_DONE BIT(1) 40 #define EXYNOS_RNG_STATUS_RNG_DONE BIT(5) 41 42 /* Five seed and output registers, each 4 bytes */ 43 #define EXYNOS_RNG_SEED_REGS 5 44 #define EXYNOS_RNG_SEED_SIZE (EXYNOS_RNG_SEED_REGS * 4) 45 46 /* 47 * Driver re-seeds itself with generated random numbers to increase 48 * the randomness. 49 * 50 * Time for next re-seed in ms. 51 */ 52 #define EXYNOS_RNG_RESEED_TIME 100 53 /* 54 * In polling mode, do not wait infinitely for the engine to finish the work. 55 */ 56 #define EXYNOS_RNG_WAIT_RETRIES 100 57 58 /* Context for crypto */ 59 struct exynos_rng_ctx { 60 struct exynos_rng_dev *rng; 61 }; 62 63 /* Device associated memory */ 64 struct exynos_rng_dev { 65 struct device *dev; 66 void __iomem *mem; 67 struct clk *clk; 68 /* Generated numbers stored for seeding during resume */ 69 u8 seed_save[EXYNOS_RNG_SEED_SIZE]; 70 unsigned int seed_save_len; 71 /* Time of last seeding in jiffies */ 72 unsigned long last_seeding; 73 }; 74 75 static struct exynos_rng_dev *exynos_rng_dev; 76 77 static u32 exynos_rng_readl(struct exynos_rng_dev *rng, u32 offset) 78 { 79 return readl_relaxed(rng->mem + offset); 80 } 81 82 static void exynos_rng_writel(struct exynos_rng_dev *rng, u32 val, u32 offset) 83 { 84 writel_relaxed(val, rng->mem + offset); 85 } 86 87 static int exynos_rng_set_seed(struct exynos_rng_dev *rng, 88 const u8 *seed, unsigned int slen) 89 { 90 u32 val; 91 int i; 92 93 /* Round seed length because loop iterates over full register size */ 94 slen = ALIGN_DOWN(slen, 4); 95 96 if (slen < EXYNOS_RNG_SEED_SIZE) 97 return -EINVAL; 98 99 for (i = 0; i < slen ; i += 4) { 100 unsigned int seed_reg = (i / 4) % EXYNOS_RNG_SEED_REGS; 101 102 val = seed[i] << 24; 103 val |= seed[i + 1] << 16; 104 val |= seed[i + 2] << 8; 105 val |= seed[i + 3] << 0; 106 107 exynos_rng_writel(rng, val, EXYNOS_RNG_SEED(seed_reg)); 108 } 109 110 val = exynos_rng_readl(rng, EXYNOS_RNG_STATUS); 111 if (!(val & EXYNOS_RNG_STATUS_SEED_SETTING_DONE)) { 112 dev_warn(rng->dev, "Seed setting not finished\n"); 113 return -EIO; 114 } 115 116 rng->last_seeding = jiffies; 117 118 return 0; 119 } 120 121 /* 122 * Read from output registers and put the data under 'dst' array, 123 * up to dlen bytes. 124 * 125 * Returns number of bytes actually stored in 'dst' (dlen 126 * or EXYNOS_RNG_SEED_SIZE). 127 */ 128 static unsigned int exynos_rng_copy_random(struct exynos_rng_dev *rng, 129 u8 *dst, unsigned int dlen) 130 { 131 unsigned int cnt = 0; 132 int i, j; 133 u32 val; 134 135 for (j = 0; j < EXYNOS_RNG_SEED_REGS; j++) { 136 val = exynos_rng_readl(rng, EXYNOS_RNG_OUT(j)); 137 138 for (i = 0; i < 4; i++) { 139 dst[cnt] = val & 0xff; 140 val >>= 8; 141 if (++cnt >= dlen) 142 return cnt; 143 } 144 } 145 146 return cnt; 147 } 148 149 /* 150 * Start the engine and poll for finish. Then read from output registers 151 * filling the 'dst' buffer up to 'dlen' bytes or up to size of generated 152 * random data (EXYNOS_RNG_SEED_SIZE). 153 * 154 * On success: return 0 and store number of read bytes under 'read' address. 155 * On error: return -ERRNO. 156 */ 157 static int exynos_rng_get_random(struct exynos_rng_dev *rng, 158 u8 *dst, unsigned int dlen, 159 unsigned int *read) 160 { 161 int retry = EXYNOS_RNG_WAIT_RETRIES; 162 163 exynos_rng_writel(rng, EXYNOS_RNG_CONTROL_START, 164 EXYNOS_RNG_CONTROL); 165 166 while (!(exynos_rng_readl(rng, 167 EXYNOS_RNG_STATUS) & EXYNOS_RNG_STATUS_RNG_DONE) && --retry) 168 cpu_relax(); 169 170 if (!retry) 171 return -ETIMEDOUT; 172 173 /* Clear status bit */ 174 exynos_rng_writel(rng, EXYNOS_RNG_STATUS_RNG_DONE, 175 EXYNOS_RNG_STATUS); 176 *read = exynos_rng_copy_random(rng, dst, dlen); 177 178 return 0; 179 } 180 181 /* Re-seed itself from time to time */ 182 static void exynos_rng_reseed(struct exynos_rng_dev *rng) 183 { 184 unsigned long next_seeding = rng->last_seeding + \ 185 msecs_to_jiffies(EXYNOS_RNG_RESEED_TIME); 186 unsigned long now = jiffies; 187 unsigned int read = 0; 188 u8 seed[EXYNOS_RNG_SEED_SIZE]; 189 190 if (time_before(now, next_seeding)) 191 return; 192 193 if (exynos_rng_get_random(rng, seed, sizeof(seed), &read)) 194 return; 195 196 exynos_rng_set_seed(rng, seed, read); 197 } 198 199 static int exynos_rng_generate(struct crypto_rng *tfm, 200 const u8 *src, unsigned int slen, 201 u8 *dst, unsigned int dlen) 202 { 203 struct exynos_rng_ctx *ctx = crypto_rng_ctx(tfm); 204 struct exynos_rng_dev *rng = ctx->rng; 205 unsigned int read = 0; 206 int ret; 207 208 ret = clk_prepare_enable(rng->clk); 209 if (ret) 210 return ret; 211 212 do { 213 ret = exynos_rng_get_random(rng, dst, dlen, &read); 214 if (ret) 215 break; 216 217 dlen -= read; 218 dst += read; 219 220 exynos_rng_reseed(rng); 221 } while (dlen > 0); 222 223 clk_disable_unprepare(rng->clk); 224 225 return ret; 226 } 227 228 static int exynos_rng_seed(struct crypto_rng *tfm, const u8 *seed, 229 unsigned int slen) 230 { 231 struct exynos_rng_ctx *ctx = crypto_rng_ctx(tfm); 232 struct exynos_rng_dev *rng = ctx->rng; 233 int ret; 234 235 ret = clk_prepare_enable(rng->clk); 236 if (ret) 237 return ret; 238 239 ret = exynos_rng_set_seed(ctx->rng, seed, slen); 240 241 clk_disable_unprepare(rng->clk); 242 243 return ret; 244 } 245 246 static int exynos_rng_kcapi_init(struct crypto_tfm *tfm) 247 { 248 struct exynos_rng_ctx *ctx = crypto_tfm_ctx(tfm); 249 250 ctx->rng = exynos_rng_dev; 251 252 return 0; 253 } 254 255 static struct rng_alg exynos_rng_alg = { 256 .generate = exynos_rng_generate, 257 .seed = exynos_rng_seed, 258 .seedsize = EXYNOS_RNG_SEED_SIZE, 259 .base = { 260 .cra_name = "stdrng", 261 .cra_driver_name = "exynos_rng", 262 .cra_priority = 100, 263 .cra_ctxsize = sizeof(struct exynos_rng_ctx), 264 .cra_module = THIS_MODULE, 265 .cra_init = exynos_rng_kcapi_init, 266 } 267 }; 268 269 static int exynos_rng_probe(struct platform_device *pdev) 270 { 271 struct exynos_rng_dev *rng; 272 struct resource *res; 273 int ret; 274 275 if (exynos_rng_dev) 276 return -EEXIST; 277 278 rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL); 279 if (!rng) 280 return -ENOMEM; 281 282 rng->dev = &pdev->dev; 283 rng->clk = devm_clk_get(&pdev->dev, "secss"); 284 if (IS_ERR(rng->clk)) { 285 dev_err(&pdev->dev, "Couldn't get clock.\n"); 286 return PTR_ERR(rng->clk); 287 } 288 289 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 290 rng->mem = devm_ioremap_resource(&pdev->dev, res); 291 if (IS_ERR(rng->mem)) 292 return PTR_ERR(rng->mem); 293 294 platform_set_drvdata(pdev, rng); 295 296 exynos_rng_dev = rng; 297 298 ret = crypto_register_rng(&exynos_rng_alg); 299 if (ret) { 300 dev_err(&pdev->dev, 301 "Couldn't register rng crypto alg: %d\n", ret); 302 exynos_rng_dev = NULL; 303 } 304 305 return ret; 306 } 307 308 static int exynos_rng_remove(struct platform_device *pdev) 309 { 310 crypto_unregister_rng(&exynos_rng_alg); 311 312 exynos_rng_dev = NULL; 313 314 return 0; 315 } 316 317 static int __maybe_unused exynos_rng_suspend(struct device *dev) 318 { 319 struct platform_device *pdev = to_platform_device(dev); 320 struct exynos_rng_dev *rng = platform_get_drvdata(pdev); 321 int ret; 322 323 /* If we were never seeded then after resume it will be the same */ 324 if (!rng->last_seeding) 325 return 0; 326 327 rng->seed_save_len = 0; 328 ret = clk_prepare_enable(rng->clk); 329 if (ret) 330 return ret; 331 332 /* Get new random numbers and store them for seeding on resume. */ 333 exynos_rng_get_random(rng, rng->seed_save, sizeof(rng->seed_save), 334 &(rng->seed_save_len)); 335 dev_dbg(rng->dev, "Stored %u bytes for seeding on system resume\n", 336 rng->seed_save_len); 337 338 clk_disable_unprepare(rng->clk); 339 340 return 0; 341 } 342 343 static int __maybe_unused exynos_rng_resume(struct device *dev) 344 { 345 struct platform_device *pdev = to_platform_device(dev); 346 struct exynos_rng_dev *rng = platform_get_drvdata(pdev); 347 int ret; 348 349 /* Never seeded so nothing to do */ 350 if (!rng->last_seeding) 351 return 0; 352 353 ret = clk_prepare_enable(rng->clk); 354 if (ret) 355 return ret; 356 357 ret = exynos_rng_set_seed(rng, rng->seed_save, rng->seed_save_len); 358 359 clk_disable_unprepare(rng->clk); 360 361 return ret; 362 } 363 364 static SIMPLE_DEV_PM_OPS(exynos_rng_pm_ops, exynos_rng_suspend, 365 exynos_rng_resume); 366 367 static const struct of_device_id exynos_rng_dt_match[] = { 368 { 369 .compatible = "samsung,exynos4-rng", 370 }, 371 { }, 372 }; 373 MODULE_DEVICE_TABLE(of, exynos_rng_dt_match); 374 375 static struct platform_driver exynos_rng_driver = { 376 .driver = { 377 .name = "exynos-rng", 378 .pm = &exynos_rng_pm_ops, 379 .of_match_table = exynos_rng_dt_match, 380 }, 381 .probe = exynos_rng_probe, 382 .remove = exynos_rng_remove, 383 }; 384 385 module_platform_driver(exynos_rng_driver); 386 387 MODULE_DESCRIPTION("Exynos H/W Random Number Generator driver"); 388 MODULE_AUTHOR("Krzysztof Kozlowski <krzk@kernel.org>"); 389 MODULE_LICENSE("GPL"); 390