Commit bbfe0c547fdf8930304104c7586903f87347150a

Authored by Eric Lee
1 parent 1a2ee265bd

Add 0006-am33x-Create-driver-for-TRNG-crypto-module.patch that wasn't part of th…

…e official PSP 04.06.00.11 release

Showing 1 changed file with 303 additions and 0 deletions Side-by-side Diff

drivers/char/hw_random/omap4-rng.c
  1 +/*
  2 + * drivers/char/hw_random/omap4-rng.c
  3 + *
  4 + * Copyright (c) 2012 Texas Instruments
  5 + * TRNG driver for OMAP4 derivatives (AM33x, etc) - Herman Schuurman <herman@ti.com>
  6 + *
  7 + * derived from omap-rng.c.
  8 + *
  9 + * Author: Deepak Saxena <dsaxena@plexity.net>
  10 + *
  11 + * Copyright 2005 (c) MontaVista Software, Inc.
  12 + *
  13 + * Mostly based on original driver:
  14 + *
  15 + * Copyright (C) 2005 Nokia Corporation
  16 + * Author: Juha Yrjölä <juha.yrjola@nokia.com>
  17 + *
  18 + * This file is licensed under the terms of the GNU General Public
  19 + * License version 2. This program is licensed "as is" without any
  20 + * warranty of any kind, whether express or implied.
  21 + */
  22 +
  23 +#include <linux/module.h>
  24 +#include <linux/init.h>
  25 +#include <linux/random.h>
  26 +#include <linux/clk.h>
  27 +#include <linux/err.h>
  28 +#include <linux/platform_device.h>
  29 +#include <linux/hw_random.h>
  30 +#include <linux/delay.h>
  31 +
  32 +#include <mach/hardware.h>
  33 +#include <asm/io.h>
  34 +
  35 +/* ==================================================================== */
  36 +/** RNG module layout.
  37 + */
  38 +/* ==================================================================== */
  39 +#define RNG_REG_OUTPUT_L 0x00
  40 +#define RNG_REG_OUTPUT_H 0x04
  41 +
  42 +#define RNG_REG_STATUS 0x08
  43 +#define RNG_REG_STATUS_NEED_CLK (1 << 31)
  44 +#define RNG_REG_STATUS_SHUTDOWN_OFLO (1 << 1)
  45 +#define RNG_REG_STATUS_RDY (1 << 0)
  46 +
  47 +#define RNG_REG_IMASK 0x0C
  48 +#define RNG_REG_IMASK_SHUTDOWN_OFLO (1 << 1)
  49 +#define RNG_REG_IMASK_RDY (1 << 0)
  50 +
  51 +#define RNG_REG_INTACK 0x10
  52 +#define RNG_REG_INTACK_SHUTDOWN_OFLO (1 << 1)
  53 +#define RNG_REG_INTACK_RDY (1 << 0)
  54 +
  55 +#define RNG_REG_CONTROL 0x14
  56 +#define RNG_REG_CONTROL_STARTUP_MASK 0xFFFF0000
  57 +#define RNG_REG_CONTROL_ENABLE_TRNG (1 << 10)
  58 +#define RNG_REG_CONTROL_NO_LFSR_FB (1 << 2)
  59 +
  60 +#define RNG_REG_CONFIG 0x18
  61 +#define RNG_REG_CONFIG_MAX_REFILL_MASK 0xFFFF0000
  62 +#define RNG_REG_CONFIG_SAMPLE_DIV 0x00000F00
  63 +#define RNG_REG_CONFIG_MIN_REFILL_MASK 0x000000FF
  64 +
  65 +#define RNG_REG_ALARMCNT 0x1C
  66 +#define RNG_REG_ALARMCNT_SHTDWN_MASK 0x3F000000
  67 +#define RNG_REG_ALARMCNT_SD_THLD_MASK 0x001F0000
  68 +#define RNG_REG_ALARMCNT_ALM_THLD_MASK 0x000000FF
  69 +
  70 +#define RNG_REG_FROENABLE 0x20
  71 +#define RNG_REG_FRODETUNE 0x24
  72 +#define RNG_REG_ALARMMASK 0x28
  73 +#define RNG_REG_ALARMSTOP 0x2C
  74 +#define RNG_REG_LFSR_L 0x30
  75 +#define RNG_REG_LFSR_M 0x34
  76 +#define RNG_REG_LFSR_H 0x38
  77 +#define RNG_REG_COUNT 0x3C
  78 +#define RNG_REG_TEST 0x40
  79 +
  80 +#define RNG_REG_OPTIONS 0x78
  81 +#define RNG_REG_OPTIONS_NUM_FROS_MASK 0x00000FC0
  82 +
  83 +#define RNG_REG_EIP_REV 0x7C
  84 +#define RNG_REG_STATUS_EN 0x1FD8
  85 +#define RNG_REG_STATUS_EN_SHUTDOWN_OFLO (1 << 1)
  86 +#define RNG_REG_STATUS_EN_RDY (1 << 0)
  87 +
  88 +#define RNG_REG_REV 0x1FE0
  89 +#define RNG_REG_REV_X_MAJOR_MASK (0x0F << 4)
  90 +#define RNG_REG_REV_Y_MINOR_MASK (0x0F << 0)
  91 +
  92 +#define RNG_REG_SYSCFG 0x1FE4
  93 +#define RNG_REG_SYSCFG_SIDLEMODE_MASK (3 << 3)
  94 +#define RNG_REG_SYSCFG_SIDLEMODE_FORCE (0 << 3)
  95 +#define RNG_REG_SYSCFG_SIDLEMODE_NO (1 << 3)
  96 +#define RNG_REG_SYSCFG_SIDLEMODE_SMART (2 << 3)
  97 +#define RNG_REG_SYSCFG_AUTOIDLE (1 << 0)
  98 +
  99 +#define RNG_REG_STATUS_SET 0x1FEC
  100 +#define RNG_REG_STATUS_SET_SHUTDOWN_OFLO (1 << 1)
  101 +#define RNG_REG_STATUS_SET_RDY (1 << 0)
  102 +
  103 +#define RNG_REG_SOFT_RESET 0x1FF0
  104 +#define RNG_REG_SOFTRESET (1 << 0)
  105 +
  106 +#define RNG_REG_IRQ_EOI 0x1FF4
  107 +#define RNG_REG_IRQ_EOI_PULSE_INT_CLEAR (1 << 0)
  108 +
  109 +#define RNG_REG_IRQSTATUS 0x1FF8
  110 +#define RNG_REG_IRQSTATUS_IRQ_EN (1 << 0)
  111 +
  112 +
  113 +static void __iomem *rng_base;
  114 +static struct clk *rng_fck;
  115 +static struct platform_device *rng_dev;
  116 +
  117 +#define trng_read(reg) \
  118 +({ \
  119 + u32 __val; \
  120 + __val = __raw_readl(rng_base + RNG_REG_##reg); \
  121 +})
  122 +
  123 +#define trng_write(val, reg) \
  124 +({ \
  125 + __raw_writel((val), rng_base + RNG_REG_##reg); \
  126 +})
  127 +
  128 +static int omap4_rng_data_read(struct hwrng *rng, void *buf, size_t max, bool wait)
  129 +{
  130 + int res, i;
  131 +
  132 + for (i = 0; i < 20; i++) {
  133 + res = trng_read(STATUS) & RNG_REG_STATUS_RDY;
  134 + if (res || !wait)
  135 + break;
  136 + /* RNG produces data fast enough (2+ MBit/sec, even
  137 + * during "rngtest" loads, that these delays don't
  138 + * seem to trigger. We *could* use the RNG IRQ, but
  139 + * that'd be higher overhead ... so why bother?
  140 + */
  141 + udelay(10);
  142 + }
  143 +
  144 + /* If we have data waiting, collect it... */
  145 + if (res) {
  146 + *(u32 *)buf = trng_read(OUTPUT_L);
  147 + buf += sizeof(u32);
  148 + *(u32 *)buf = trng_read(OUTPUT_H);
  149 +
  150 + trng_write(RNG_REG_INTACK_RDY, INTACK);
  151 +
  152 + res = 2 * sizeof(u32);
  153 + }
  154 + return res;
  155 +}
  156 +
  157 +static struct hwrng omap4_rng_ops = {
  158 + .name = "omap4",
  159 + .read = omap4_rng_data_read,
  160 +};
  161 +
  162 +static int __devinit omap4_rng_probe(struct platform_device *pdev)
  163 +{
  164 + struct resource *res;
  165 + int ret;
  166 + u32 reg;
  167 +
  168 + /*
  169 + * A bit ugly, and it will never actually happen but there can
  170 + * be only one RNG and this catches any bork
  171 + */
  172 + if (rng_dev)
  173 + return -EBUSY;
  174 +
  175 + rng_fck = clk_get(&pdev->dev, "rng_fck");
  176 + if (IS_ERR(rng_fck)) {
  177 + dev_err(&pdev->dev, "Could not get rng_fck\n");
  178 + ret = PTR_ERR(rng_fck);
  179 + return ret;
  180 + } else
  181 + clk_enable(rng_fck);
  182 +
  183 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  184 + if (!res) {
  185 + ret = -ENOENT;
  186 + goto err_region;
  187 + }
  188 +
  189 + if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
  190 + ret = -EBUSY;
  191 + goto err_region;
  192 + }
  193 +
  194 + dev_set_drvdata(&pdev->dev, res);
  195 + rng_base = ioremap(res->start, resource_size(res));
  196 + if (!rng_base) {
  197 + ret = -ENOMEM;
  198 + goto err_ioremap;
  199 + }
  200 +
  201 + ret = hwrng_register(&omap4_rng_ops);
  202 + if (ret)
  203 + goto err_register;
  204 +
  205 + reg = trng_read(REV);
  206 + dev_info(&pdev->dev, "OMAP4 Random Number Generator ver. %u.%02u\n",
  207 + ((reg & RNG_REG_REV_X_MAJOR_MASK) >> 4),
  208 + (reg & RNG_REG_REV_Y_MINOR_MASK));
  209 +
  210 + rng_dev = pdev;
  211 +
  212 + /* start TRNG if not running yet */
  213 + if (!(trng_read(CONTROL) & RNG_REG_CONTROL_ENABLE_TRNG)) {
  214 + trng_write(0x00220021, CONFIG);
  215 + trng_write(0x00210400, CONTROL);
  216 + }
  217 +
  218 + return 0;
  219 +
  220 +err_register:
  221 + iounmap(rng_base);
  222 + rng_base = NULL;
  223 +err_ioremap:
  224 + release_mem_region(res->start, resource_size(res));
  225 +err_region:
  226 + clk_disable(rng_fck);
  227 + clk_put(rng_fck);
  228 + return ret;
  229 +}
  230 +
  231 +static int __exit omap4_rng_remove(struct platform_device *pdev)
  232 +{
  233 + struct resource *res = dev_get_drvdata(&pdev->dev);
  234 +
  235 + hwrng_unregister(&omap4_rng_ops);
  236 +
  237 + trng_write(trng_read(CONTROL) & ~RNG_REG_CONTROL_ENABLE_TRNG, CONTROL);
  238 +
  239 + iounmap(rng_base);
  240 +
  241 + clk_disable(rng_fck);
  242 + clk_put(rng_fck);
  243 + release_mem_region(res->start, resource_size(res));
  244 + rng_base = NULL;
  245 +
  246 + return 0;
  247 +}
  248 +
  249 +#ifdef CONFIG_PM
  250 +
  251 +static int omap4_rng_suspend(struct platform_device *pdev, pm_message_t message)
  252 +{
  253 + trng_write(trng_read(CONTROL) & ~RNG_REG_CONTROL_ENABLE_TRNG, CONTROL);
  254 +
  255 + return 0;
  256 +}
  257 +
  258 +static int omap4_rng_resume(struct platform_device *pdev)
  259 +{
  260 + trng_write(trng_read(CONTROL) | RNG_REG_CONTROL_ENABLE_TRNG, CONTROL);
  261 +
  262 + return 0;
  263 +}
  264 +
  265 +#else
  266 +
  267 +#define omap4_rng_suspend NULL
  268 +#define omap4_rng_resume NULL
  269 +
  270 +#endif
  271 +
  272 +/* work with hotplug and coldplug */
  273 +MODULE_ALIAS("platform:omap4_rng");
  274 +
  275 +static struct platform_driver omap4_rng_driver = {
  276 + .driver = {
  277 + .name = "omap4_rng",
  278 + .owner = THIS_MODULE,
  279 + },
  280 + .probe = omap4_rng_probe,
  281 + .remove = __exit_p(omap4_rng_remove),
  282 + .suspend = omap4_rng_suspend,
  283 + .resume = omap4_rng_resume
  284 +};
  285 +
  286 +static int __init omap4_rng_init(void)
  287 +{
  288 + if (!cpu_is_am33xx() || omap_type() != OMAP2_DEVICE_TYPE_GP)
  289 + return -ENODEV;
  290 +
  291 + return platform_driver_register(&omap4_rng_driver);
  292 +}
  293 +
  294 +static void __exit omap4_rng_exit(void)
  295 +{
  296 + platform_driver_unregister(&omap4_rng_driver);
  297 +}
  298 +
  299 +module_init(omap4_rng_init);
  300 +module_exit(omap4_rng_exit);
  301 +
  302 +MODULE_LICENSE("GPL");
  303 +MODULE_DESCRIPTION("AM33X TRNG driver");