|
@@ -28,6 +28,7 @@
|
|
|
#include <linux/of_device.h>
|
|
|
#include <linux/of_address.h>
|
|
|
#include <linux/interrupt.h>
|
|
|
+#include <linux/clk.h>
|
|
|
|
|
|
#include <asm/io.h>
|
|
|
|
|
@@ -63,6 +64,7 @@
|
|
|
|
|
|
#define OMAP2_RNG_OUTPUT_SIZE 0x4
|
|
|
#define OMAP4_RNG_OUTPUT_SIZE 0x8
|
|
|
+#define EIP76_RNG_OUTPUT_SIZE 0x10
|
|
|
|
|
|
enum {
|
|
|
RNG_OUTPUT_0_REG = 0,
|
|
@@ -108,6 +110,23 @@ static const u16 reg_map_omap4[] = {
|
|
|
[RNG_SYSCONFIG_REG] = 0x1FE4,
|
|
|
};
|
|
|
|
|
|
+static const u16 reg_map_eip76[] = {
|
|
|
+ [RNG_OUTPUT_0_REG] = 0x0,
|
|
|
+ [RNG_OUTPUT_1_REG] = 0x4,
|
|
|
+ [RNG_OUTPUT_2_REG] = 0x8,
|
|
|
+ [RNG_OUTPUT_3_REG] = 0xc,
|
|
|
+ [RNG_STATUS_REG] = 0x10,
|
|
|
+ [RNG_INTACK_REG] = 0x10,
|
|
|
+ [RNG_CONTROL_REG] = 0x14,
|
|
|
+ [RNG_CONFIG_REG] = 0x18,
|
|
|
+ [RNG_ALARMCNT_REG] = 0x1c,
|
|
|
+ [RNG_FROENABLE_REG] = 0x20,
|
|
|
+ [RNG_FRODETUNE_REG] = 0x24,
|
|
|
+ [RNG_ALARMMASK_REG] = 0x28,
|
|
|
+ [RNG_ALARMSTOP_REG] = 0x2c,
|
|
|
+ [RNG_REV_REG] = 0x7c,
|
|
|
+};
|
|
|
+
|
|
|
struct omap_rng_dev;
|
|
|
/**
|
|
|
* struct omap_rng_pdata - RNG IP block-specific data
|
|
@@ -130,6 +149,7 @@ struct omap_rng_dev {
|
|
|
struct device *dev;
|
|
|
const struct omap_rng_pdata *pdata;
|
|
|
struct hwrng rng;
|
|
|
+ struct clk *clk;
|
|
|
};
|
|
|
|
|
|
static inline u32 omap_rng_read(struct omap_rng_dev *priv, u16 reg)
|
|
@@ -221,6 +241,38 @@ static inline u32 omap4_rng_data_present(struct omap_rng_dev *priv)
|
|
|
return omap_rng_read(priv, RNG_STATUS_REG) & RNG_REG_STATUS_RDY;
|
|
|
}
|
|
|
|
|
|
+static int eip76_rng_init(struct omap_rng_dev *priv)
|
|
|
+{
|
|
|
+ u32 val;
|
|
|
+
|
|
|
+ /* Return if RNG is already running. */
|
|
|
+ if (omap_rng_read(priv, RNG_CONTROL_REG) & RNG_CONTROL_ENABLE_TRNG_MASK)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ /* Number of 512 bit blocks of raw Noise Source output data that must
|
|
|
+ * be processed by either the Conditioning Function or the
|
|
|
+ * SP 800-90 DRBG ‘BC_DF’ functionality to yield a ‘full entropy’
|
|
|
+ * output value.
|
|
|
+ */
|
|
|
+ val = 0x5 << RNG_CONFIG_MIN_REFIL_CYCLES_SHIFT;
|
|
|
+
|
|
|
+ /* Number of FRO samples that are XOR-ed together into one bit to be
|
|
|
+ * shifted into the main shift register
|
|
|
+ */
|
|
|
+ val |= RNG_CONFIG_MAX_REFIL_CYCLES << RNG_CONFIG_MAX_REFIL_CYCLES_SHIFT;
|
|
|
+ omap_rng_write(priv, RNG_CONFIG_REG, val);
|
|
|
+
|
|
|
+ /* Enable all available FROs */
|
|
|
+ omap_rng_write(priv, RNG_FRODETUNE_REG, 0x0);
|
|
|
+ omap_rng_write(priv, RNG_FROENABLE_REG, RNG_REG_FROENABLE_MASK);
|
|
|
+
|
|
|
+ /* Enable TRNG */
|
|
|
+ val = RNG_CONTROL_ENABLE_TRNG_MASK;
|
|
|
+ omap_rng_write(priv, RNG_CONTROL_REG, val);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int omap4_rng_init(struct omap_rng_dev *priv)
|
|
|
{
|
|
|
u32 val;
|
|
@@ -290,6 +342,14 @@ static struct omap_rng_pdata omap4_rng_pdata = {
|
|
|
.cleanup = omap4_rng_cleanup,
|
|
|
};
|
|
|
|
|
|
+static struct omap_rng_pdata eip76_rng_pdata = {
|
|
|
+ .regs = (u16 *)reg_map_eip76,
|
|
|
+ .data_size = EIP76_RNG_OUTPUT_SIZE,
|
|
|
+ .data_present = omap4_rng_data_present,
|
|
|
+ .init = eip76_rng_init,
|
|
|
+ .cleanup = omap4_rng_cleanup,
|
|
|
+};
|
|
|
+
|
|
|
static const struct of_device_id omap_rng_of_match[] = {
|
|
|
{
|
|
|
.compatible = "ti,omap2-rng",
|
|
@@ -299,6 +359,10 @@ static const struct of_device_id omap_rng_of_match[] = {
|
|
|
.compatible = "ti,omap4-rng",
|
|
|
.data = &omap4_rng_pdata,
|
|
|
},
|
|
|
+ {
|
|
|
+ .compatible = "inside-secure,safexcel-eip76",
|
|
|
+ .data = &eip76_rng_pdata,
|
|
|
+ },
|
|
|
{},
|
|
|
};
|
|
|
MODULE_DEVICE_TABLE(of, omap_rng_of_match);
|
|
@@ -317,7 +381,8 @@ static int of_get_omap_rng_device_details(struct omap_rng_dev *priv,
|
|
|
}
|
|
|
priv->pdata = match->data;
|
|
|
|
|
|
- if (of_device_is_compatible(dev->of_node, "ti,omap4-rng")) {
|
|
|
+ if (of_device_is_compatible(dev->of_node, "ti,omap4-rng") ||
|
|
|
+ of_device_is_compatible(dev->of_node, "inside-secure,safexcel-eip76")) {
|
|
|
irq = platform_get_irq(pdev, 0);
|
|
|
if (irq < 0) {
|
|
|
dev_err(dev, "%s: error getting IRQ resource - %d\n",
|
|
@@ -333,6 +398,16 @@ static int of_get_omap_rng_device_details(struct omap_rng_dev *priv,
|
|
|
return err;
|
|
|
}
|
|
|
omap_rng_write(priv, RNG_INTMASK_REG, RNG_SHUTDOWN_OFLO_MASK);
|
|
|
+
|
|
|
+ priv->clk = of_clk_get(pdev->dev.of_node, 0);
|
|
|
+ if (IS_ERR(priv->clk) && PTR_ERR(priv->clk) == -EPROBE_DEFER)
|
|
|
+ return -EPROBE_DEFER;
|
|
|
+ if (!IS_ERR(priv->clk)) {
|
|
|
+ err = clk_prepare_enable(priv->clk);
|
|
|
+ if (err)
|
|
|
+ dev_err(&pdev->dev, "unable to enable the clk, "
|
|
|
+ "err = %d\n", err);
|
|
|
+ }
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
@@ -394,7 +469,7 @@ static int omap_rng_probe(struct platform_device *pdev)
|
|
|
ret = (dev->of_node) ? of_get_omap_rng_device_details(priv, pdev) :
|
|
|
get_omap_rng_device_details(priv);
|
|
|
if (ret)
|
|
|
- goto err_ioremap;
|
|
|
+ goto err_register;
|
|
|
|
|
|
ret = hwrng_register(&priv->rng);
|
|
|
if (ret)
|
|
@@ -407,7 +482,11 @@ static int omap_rng_probe(struct platform_device *pdev)
|
|
|
|
|
|
err_register:
|
|
|
priv->base = NULL;
|
|
|
+ pm_runtime_put_sync(&pdev->dev);
|
|
|
pm_runtime_disable(&pdev->dev);
|
|
|
+
|
|
|
+ if (!IS_ERR(priv->clk))
|
|
|
+ clk_disable_unprepare(priv->clk);
|
|
|
err_ioremap:
|
|
|
dev_err(dev, "initialization failed.\n");
|
|
|
return ret;
|
|
@@ -424,6 +503,9 @@ static int omap_rng_remove(struct platform_device *pdev)
|
|
|
pm_runtime_put_sync(&pdev->dev);
|
|
|
pm_runtime_disable(&pdev->dev);
|
|
|
|
|
|
+ if (!IS_ERR(priv->clk))
|
|
|
+ clk_disable_unprepare(priv->clk);
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|