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