2 * Random Number Generator driver for the Keystone SOC
4 * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com
6 * Authors: Sandeep Nair
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * version 2 as published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
19 #include <linux/hw_random.h>
20 #include <linux/kernel.h>
21 #include <linux/module.h>
23 #include <linux/platform_device.h>
24 #include <linux/clk.h>
25 #include <linux/pm_runtime.h>
26 #include <linux/err.h>
27 #include <linux/regmap.h>
28 #include <linux/mfd/syscon.h>
30 #include <linux/of_address.h>
31 #include <linux/delay.h>
33 #define SA_CMD_STATUS_OFS 0x8
35 /* TRNG enable control in SA System module*/
36 #define SA_CMD_STATUS_REG_TRNG_ENABLE BIT(3)
38 /* TRNG start control in TRNG module */
39 #define TRNG_CNTL_REG_TRNG_ENABLE BIT(10)
41 /* Data ready indicator in STATUS register */
42 #define TRNG_STATUS_REG_READY BIT(0)
44 /* Data ready clear control in INTACK register */
45 #define TRNG_INTACK_REG_READY BIT(0)
48 * Number of samples taken to gather entropy during startup.
49 * If value is 0, the number of samples is 2^24 else
50 * equals value times 2^8.
52 #define TRNG_DEF_STARTUP_CYCLES 0
53 #define TRNG_CNTL_REG_STARTUP_CYCLES_SHIFT 16
56 * Minimum number of samples taken to regenerate entropy
57 * If value is 0, the number of samples is 2^24 else
58 * equals value times 2^6.
60 #define TRNG_DEF_MIN_REFILL_CYCLES 1
61 #define TRNG_CFG_REG_MIN_REFILL_CYCLES_SHIFT 0
64 * Maximum number of samples taken to regenerate entropy
65 * If value is 0, the number of samples is 2^24 else
66 * equals value times 2^8.
68 #define TRNG_DEF_MAX_REFILL_CYCLES 0
69 #define TRNG_CFG_REG_MAX_REFILL_CYCLES_SHIFT 16
71 /* Number of CLK input cycles between samples */
72 #define TRNG_DEF_CLK_DIV_CYCLES 0
73 #define TRNG_CFG_REG_SAMPLE_DIV_SHIFT 8
75 /* Maximum retries to get rng data */
76 #define SA_MAX_RNG_DATA_RETRIES 5
77 /* Delay between retries (in usecs) */
78 #define SA_RNG_DATA_RETRY_DELAY 5
94 struct regmap
*regmap_cfg
;
95 struct trng_regs
*reg_rng
;
98 static int ks_sa_rng_init(struct hwrng
*rng
)
101 struct device
*dev
= (struct device
*)rng
->priv
;
102 struct ks_sa_rng
*ks_sa_rng
= dev_get_drvdata(dev
);
104 /* Enable RNG module */
105 regmap_write_bits(ks_sa_rng
->regmap_cfg
, SA_CMD_STATUS_OFS
,
106 SA_CMD_STATUS_REG_TRNG_ENABLE
,
107 SA_CMD_STATUS_REG_TRNG_ENABLE
);
109 /* Configure RNG module */
110 writel(0, &ks_sa_rng
->reg_rng
->control
);
111 value
= TRNG_DEF_STARTUP_CYCLES
<< TRNG_CNTL_REG_STARTUP_CYCLES_SHIFT
;
112 writel(value
, &ks_sa_rng
->reg_rng
->control
);
114 value
= (TRNG_DEF_MIN_REFILL_CYCLES
<<
115 TRNG_CFG_REG_MIN_REFILL_CYCLES_SHIFT
) |
116 (TRNG_DEF_MAX_REFILL_CYCLES
<<
117 TRNG_CFG_REG_MAX_REFILL_CYCLES_SHIFT
) |
118 (TRNG_DEF_CLK_DIV_CYCLES
<<
119 TRNG_CFG_REG_SAMPLE_DIV_SHIFT
);
121 writel(value
, &ks_sa_rng
->reg_rng
->config
);
123 /* Disable all interrupts from TRNG */
124 writel(0, &ks_sa_rng
->reg_rng
->intmask
);
127 value
= readl(&ks_sa_rng
->reg_rng
->control
);
128 value
|= TRNG_CNTL_REG_TRNG_ENABLE
;
129 writel(value
, &ks_sa_rng
->reg_rng
->control
);
134 static void ks_sa_rng_cleanup(struct hwrng
*rng
)
136 struct device
*dev
= (struct device
*)rng
->priv
;
137 struct ks_sa_rng
*ks_sa_rng
= dev_get_drvdata(dev
);
140 writel(0, &ks_sa_rng
->reg_rng
->control
);
141 regmap_write_bits(ks_sa_rng
->regmap_cfg
, SA_CMD_STATUS_OFS
,
142 SA_CMD_STATUS_REG_TRNG_ENABLE
, 0);
145 static int ks_sa_rng_data_read(struct hwrng
*rng
, u32
*data
)
147 struct device
*dev
= (struct device
*)rng
->priv
;
148 struct ks_sa_rng
*ks_sa_rng
= dev_get_drvdata(dev
);
150 /* Read random data */
151 data
[0] = readl(&ks_sa_rng
->reg_rng
->output_l
);
152 data
[1] = readl(&ks_sa_rng
->reg_rng
->output_h
);
154 writel(TRNG_INTACK_REG_READY
, &ks_sa_rng
->reg_rng
->intack
);
156 return sizeof(u32
) * 2;
159 static int ks_sa_rng_data_present(struct hwrng
*rng
, int wait
)
161 struct device
*dev
= (struct device
*)rng
->priv
;
162 struct ks_sa_rng
*ks_sa_rng
= dev_get_drvdata(dev
);
167 for (j
= 0; j
< SA_MAX_RNG_DATA_RETRIES
; j
++) {
168 ready
= readl(&ks_sa_rng
->reg_rng
->status
);
169 ready
&= TRNG_STATUS_REG_READY
;
174 udelay(SA_RNG_DATA_RETRY_DELAY
);
180 static int ks_sa_rng_probe(struct platform_device
*pdev
)
182 struct ks_sa_rng
*ks_sa_rng
;
183 struct device
*dev
= &pdev
->dev
;
185 struct resource
*mem
;
187 ks_sa_rng
= devm_kzalloc(dev
, sizeof(*ks_sa_rng
), GFP_KERNEL
);
191 ks_sa_rng
->dev
= dev
;
192 ks_sa_rng
->rng
= (struct hwrng
) {
193 .name
= "ks_sa_hwrng",
194 .init
= ks_sa_rng_init
,
195 .data_read
= ks_sa_rng_data_read
,
196 .data_present
= ks_sa_rng_data_present
,
197 .cleanup
= ks_sa_rng_cleanup
,
199 ks_sa_rng
->rng
.priv
= (unsigned long)dev
;
201 mem
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
202 ks_sa_rng
->reg_rng
= devm_ioremap_resource(dev
, mem
);
203 if (IS_ERR(ks_sa_rng
->reg_rng
))
204 return PTR_ERR(ks_sa_rng
->reg_rng
);
206 ks_sa_rng
->regmap_cfg
=
207 syscon_regmap_lookup_by_phandle(dev
->of_node
,
210 if (IS_ERR(ks_sa_rng
->regmap_cfg
)) {
211 dev_err(dev
, "syscon_node_to_regmap failed\n");
215 pm_runtime_enable(dev
);
216 ret
= pm_runtime_get_sync(dev
);
218 dev_err(dev
, "Failed to enable SA power-domain\n");
219 pm_runtime_disable(dev
);
223 platform_set_drvdata(pdev
, ks_sa_rng
);
225 return devm_hwrng_register(&pdev
->dev
, &ks_sa_rng
->rng
);
228 static int ks_sa_rng_remove(struct platform_device
*pdev
)
230 pm_runtime_put_sync(&pdev
->dev
);
231 pm_runtime_disable(&pdev
->dev
);
236 static const struct of_device_id ks_sa_rng_dt_match
[] = {
238 .compatible
= "ti,keystone-rng",
242 MODULE_DEVICE_TABLE(of
, ks_sa_rng_dt_match
);
244 static struct platform_driver ks_sa_rng_driver
= {
247 .of_match_table
= ks_sa_rng_dt_match
,
249 .probe
= ks_sa_rng_probe
,
250 .remove
= ks_sa_rng_remove
,
253 module_platform_driver(ks_sa_rng_driver
);
255 MODULE_DESCRIPTION("Keystone NETCP SA H/W Random Number Generator driver");
256 MODULE_AUTHOR("Vitaly Andrianov <vitalya@ti.com>");
257 MODULE_LICENSE("GPL");