Merge git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
Pull crypto updates from Herbert Xu: "API: - Add library interfaces of certain crypto algorithms for WireGuard - Remove the obsolete ablkcipher and blkcipher interfaces - Move add_early_randomness() out of rng_mutex Algorithms: - Add blake2b shash algorithm - Add blake2s shash algorithm - Add curve25519 kpp algorithm - Implement 4 way interleave in arm64/gcm-ce - Implement ciphertext stealing in powerpc/spe-xts - Add Eric Biggers's scalar accelerated ChaCha code for ARM - Add accelerated 32r2 code from Zinc for MIPS - Add OpenSSL/CRYPTOGRAMS poly1305 implementation for ARM and MIPS Drivers: - Fix entropy reading failures in ks-sa - Add support for sam9x60 in atmel - Add crypto accelerator for amlogic GXL - Add sun8i-ce Crypto Engine - Add sun8i-ss cryptographic offloader - Add a host of algorithms to inside-secure - Add NPCM RNG driver - add HiSilicon HPRE accelerator - Add HiSilicon TRNG driver" * git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6: (285 commits) crypto: vmx - Avoid weird build failures crypto: lib/chacha20poly1305 - use chacha20_crypt() crypto: x86/chacha - only unregister algorithms if registered crypto: chacha_generic - remove unnecessary setkey() functions crypto: amlogic - enable working on big endian kernel crypto: sun8i-ce - enable working on big endian crypto: mips/chacha - select CRYPTO_SKCIPHER, not CRYPTO_BLKCIPHER hwrng: ks-sa - Enable COMPILE_TEST crypto: essiv - remove redundant null pointer check before kfree crypto: atmel-aes - Change data type for "lastc" buffer crypto: atmel-tdes - Set the IV after {en,de}crypt crypto: sun4i-ss - fix big endian issues crypto: sun4i-ss - hide the Invalid keylen message crypto: sun4i-ss - use crypto_ahash_digestsize crypto: sun4i-ss - remove dependency on not 64BIT crypto: sun4i-ss - Fix 64-bit size_t warnings on sun4i-ss-hash.c MAINTAINERS: Add maintainer for HiSilicon SEC V2 driver crypto: hisilicon - add DebugFS for HiSilicon SEC Documentation: add DebugFS doc for HiSilicon SEC crypto: hisilicon - add SRIOV for HiSilicon SEC ...
Esse commit está contido em:
@@ -308,6 +308,19 @@ config HW_RANDOM_HISI
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
config HW_RANDOM_HISI_V2
|
||||
tristate "HiSilicon True Random Number Generator V2 support"
|
||||
depends on HW_RANDOM && ARM64 && ACPI
|
||||
default HW_RANDOM
|
||||
help
|
||||
This driver provides kernel-side support for the True Random Number
|
||||
Generator V2 hardware found on HiSilicon Hi1620 SoC.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called hisi-trng-v2.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
config HW_RANDOM_ST
|
||||
tristate "ST Microelectronics HW Random Number Generator support"
|
||||
depends on HW_RANDOM && ARCH_STI
|
||||
@@ -440,6 +453,19 @@ config HW_RANDOM_OPTEE
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
config HW_RANDOM_NPCM
|
||||
tristate "NPCM Random Number Generator support"
|
||||
depends on ARCH_NPCM || COMPILE_TEST
|
||||
default HW_RANDOM
|
||||
help
|
||||
This driver provides support for the Random Number
|
||||
Generator hardware available in Nuvoton NPCM SoCs.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called npcm-rng.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
endif # HW_RANDOM
|
||||
|
||||
config UML_RANDOM
|
||||
@@ -458,7 +484,7 @@ config UML_RANDOM
|
||||
/dev/hwrng and injects the entropy into /dev/random.
|
||||
|
||||
config HW_RANDOM_KEYSTONE
|
||||
depends on ARCH_KEYSTONE
|
||||
depends on ARCH_KEYSTONE || COMPILE_TEST
|
||||
default HW_RANDOM
|
||||
tristate "TI Keystone NETCP SA Hardware random number generator"
|
||||
help
|
||||
|
@@ -27,6 +27,7 @@ obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o
|
||||
obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o
|
||||
obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o
|
||||
obj-$(CONFIG_HW_RANDOM_HISI) += hisi-rng.o
|
||||
obj-$(CONFIG_HW_RANDOM_HISI_V2) += hisi-trng-v2.o
|
||||
obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o
|
||||
obj-$(CONFIG_HW_RANDOM_IPROC_RNG200) += iproc-rng200.o
|
||||
obj-$(CONFIG_HW_RANDOM_ST) += st-rng.o
|
||||
@@ -39,3 +40,4 @@ obj-$(CONFIG_HW_RANDOM_MTK) += mtk-rng.o
|
||||
obj-$(CONFIG_HW_RANDOM_S390) += s390-trng.o
|
||||
obj-$(CONFIG_HW_RANDOM_KEYSTONE) += ks-sa-rng.o
|
||||
obj-$(CONFIG_HW_RANDOM_OPTEE) += optee-rng.o
|
||||
obj-$(CONFIG_HW_RANDOM_NPCM) += npcm-rng.o
|
||||
|
@@ -14,14 +14,22 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/hw_random.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define TRNG_CR 0x00
|
||||
#define TRNG_MR 0x04
|
||||
#define TRNG_ISR 0x1c
|
||||
#define TRNG_ODATA 0x50
|
||||
|
||||
#define TRNG_KEY 0x524e4700 /* RNG */
|
||||
|
||||
#define TRNG_HALFR BIT(0) /* generate RN every 168 cycles */
|
||||
|
||||
struct atmel_trng_data {
|
||||
bool has_half_rate;
|
||||
};
|
||||
|
||||
struct atmel_trng {
|
||||
struct clk *clk;
|
||||
void __iomem *base;
|
||||
@@ -62,21 +70,31 @@ static void atmel_trng_disable(struct atmel_trng *trng)
|
||||
static int atmel_trng_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct atmel_trng *trng;
|
||||
struct resource *res;
|
||||
const struct atmel_trng_data *data;
|
||||
int ret;
|
||||
|
||||
trng = devm_kzalloc(&pdev->dev, sizeof(*trng), GFP_KERNEL);
|
||||
if (!trng)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
trng->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
trng->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(trng->base))
|
||||
return PTR_ERR(trng->base);
|
||||
|
||||
trng->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(trng->clk))
|
||||
return PTR_ERR(trng->clk);
|
||||
data = of_device_get_match_data(&pdev->dev);
|
||||
if (!data)
|
||||
return -ENODEV;
|
||||
|
||||
if (data->has_half_rate) {
|
||||
unsigned long rate = clk_get_rate(trng->clk);
|
||||
|
||||
/* if peripheral clk is above 100MHz, set HALFR */
|
||||
if (rate > 100000000)
|
||||
writel(TRNG_HALFR, trng->base + TRNG_MR);
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(trng->clk);
|
||||
if (ret)
|
||||
@@ -141,9 +159,24 @@ static const struct dev_pm_ops atmel_trng_pm_ops = {
|
||||
};
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static const struct atmel_trng_data at91sam9g45_config = {
|
||||
.has_half_rate = false,
|
||||
};
|
||||
|
||||
static const struct atmel_trng_data sam9x60_config = {
|
||||
.has_half_rate = true,
|
||||
};
|
||||
|
||||
static const struct of_device_id atmel_trng_dt_ids[] = {
|
||||
{ .compatible = "atmel,at91sam9g45-trng" },
|
||||
{ /* sentinel */ }
|
||||
{
|
||||
.compatible = "atmel,at91sam9g45-trng",
|
||||
.data = &at91sam9g45_config,
|
||||
}, {
|
||||
.compatible = "microchip,sam9x60-trng",
|
||||
.data = &sam9x60_config,
|
||||
}, {
|
||||
/* sentinel */
|
||||
}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, atmel_trng_dt_ids);
|
||||
|
||||
|
@@ -142,7 +142,6 @@ static int bcm2835_rng_probe(struct platform_device *pdev)
|
||||
struct device_node *np = dev->of_node;
|
||||
const struct of_device_id *rng_id;
|
||||
struct bcm2835_rng_priv *priv;
|
||||
struct resource *r;
|
||||
int err;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
@@ -151,10 +150,8 @@ static int bcm2835_rng_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
|
||||
/* map peripheral */
|
||||
priv->base = devm_ioremap_resource(dev, r);
|
||||
priv->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(priv->base))
|
||||
return PTR_ERR(priv->base);
|
||||
|
||||
|
@@ -111,6 +111,14 @@ static void drop_current_rng(void)
|
||||
}
|
||||
|
||||
/* Returns ERR_PTR(), NULL or refcounted hwrng */
|
||||
static struct hwrng *get_current_rng_nolock(void)
|
||||
{
|
||||
if (current_rng)
|
||||
kref_get(¤t_rng->ref);
|
||||
|
||||
return current_rng;
|
||||
}
|
||||
|
||||
static struct hwrng *get_current_rng(void)
|
||||
{
|
||||
struct hwrng *rng;
|
||||
@@ -118,9 +126,7 @@ static struct hwrng *get_current_rng(void)
|
||||
if (mutex_lock_interruptible(&rng_mutex))
|
||||
return ERR_PTR(-ERESTARTSYS);
|
||||
|
||||
rng = current_rng;
|
||||
if (rng)
|
||||
kref_get(&rng->ref);
|
||||
rng = get_current_rng_nolock();
|
||||
|
||||
mutex_unlock(&rng_mutex);
|
||||
return rng;
|
||||
@@ -155,8 +161,6 @@ static int hwrng_init(struct hwrng *rng)
|
||||
reinit_completion(&rng->cleanup_done);
|
||||
|
||||
skip_init:
|
||||
add_early_randomness(rng);
|
||||
|
||||
current_quality = rng->quality ? : default_quality;
|
||||
if (current_quality > 1024)
|
||||
current_quality = 1024;
|
||||
@@ -320,12 +324,13 @@ static ssize_t hwrng_attr_current_store(struct device *dev,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
int err = -ENODEV;
|
||||
struct hwrng *rng;
|
||||
struct hwrng *rng, *old_rng, *new_rng;
|
||||
|
||||
err = mutex_lock_interruptible(&rng_mutex);
|
||||
if (err)
|
||||
return -ERESTARTSYS;
|
||||
|
||||
old_rng = current_rng;
|
||||
if (sysfs_streq(buf, "")) {
|
||||
err = enable_best_rng();
|
||||
} else {
|
||||
@@ -337,9 +342,15 @@ static ssize_t hwrng_attr_current_store(struct device *dev,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
new_rng = get_current_rng_nolock();
|
||||
mutex_unlock(&rng_mutex);
|
||||
|
||||
if (new_rng) {
|
||||
if (new_rng != old_rng)
|
||||
add_early_randomness(new_rng);
|
||||
put_rng(new_rng);
|
||||
}
|
||||
|
||||
return err ? : len;
|
||||
}
|
||||
|
||||
@@ -457,13 +468,15 @@ static void start_khwrngd(void)
|
||||
int hwrng_register(struct hwrng *rng)
|
||||
{
|
||||
int err = -EINVAL;
|
||||
struct hwrng *old_rng, *tmp;
|
||||
struct hwrng *tmp;
|
||||
struct list_head *rng_list_ptr;
|
||||
bool is_new_current = false;
|
||||
|
||||
if (!rng->name || (!rng->data_read && !rng->read))
|
||||
goto out;
|
||||
|
||||
mutex_lock(&rng_mutex);
|
||||
|
||||
/* Must not register two RNGs with the same name. */
|
||||
err = -EEXIST;
|
||||
list_for_each_entry(tmp, &rng_list, list) {
|
||||
@@ -482,10 +495,8 @@ int hwrng_register(struct hwrng *rng)
|
||||
}
|
||||
list_add_tail(&rng->list, rng_list_ptr);
|
||||
|
||||
old_rng = current_rng;
|
||||
err = 0;
|
||||
if (!old_rng ||
|
||||
(!cur_rng_set_by_user && rng->quality > old_rng->quality)) {
|
||||
if (!current_rng ||
|
||||
(!cur_rng_set_by_user && rng->quality > current_rng->quality)) {
|
||||
/*
|
||||
* Set new rng as current as the new rng source
|
||||
* provides better entropy quality and was not
|
||||
@@ -494,19 +505,26 @@ int hwrng_register(struct hwrng *rng)
|
||||
err = set_current_rng(rng);
|
||||
if (err)
|
||||
goto out_unlock;
|
||||
/* to use current_rng in add_early_randomness() we need
|
||||
* to take a ref
|
||||
*/
|
||||
is_new_current = true;
|
||||
kref_get(&rng->ref);
|
||||
}
|
||||
|
||||
if (old_rng && !rng->init) {
|
||||
mutex_unlock(&rng_mutex);
|
||||
if (is_new_current || !rng->init) {
|
||||
/*
|
||||
* Use a new device's input to add some randomness to
|
||||
* the system. If this rng device isn't going to be
|
||||
* used right away, its init function hasn't been
|
||||
* called yet; so only use the randomness from devices
|
||||
* that don't need an init callback.
|
||||
* called yet by set_current_rng(); so only use the
|
||||
* randomness from devices that don't need an init callback
|
||||
*/
|
||||
add_early_randomness(rng);
|
||||
}
|
||||
|
||||
if (is_new_current)
|
||||
put_rng(rng);
|
||||
return 0;
|
||||
out_unlock:
|
||||
mutex_unlock(&rng_mutex);
|
||||
out:
|
||||
@@ -516,10 +534,12 @@ EXPORT_SYMBOL_GPL(hwrng_register);
|
||||
|
||||
void hwrng_unregister(struct hwrng *rng)
|
||||
{
|
||||
struct hwrng *old_rng, *new_rng;
|
||||
int err;
|
||||
|
||||
mutex_lock(&rng_mutex);
|
||||
|
||||
old_rng = current_rng;
|
||||
list_del(&rng->list);
|
||||
if (current_rng == rng) {
|
||||
err = enable_best_rng();
|
||||
@@ -529,6 +549,7 @@ void hwrng_unregister(struct hwrng *rng)
|
||||
}
|
||||
}
|
||||
|
||||
new_rng = get_current_rng_nolock();
|
||||
if (list_empty(&rng_list)) {
|
||||
mutex_unlock(&rng_mutex);
|
||||
if (hwrng_fill)
|
||||
@@ -536,6 +557,12 @@ void hwrng_unregister(struct hwrng *rng)
|
||||
} else
|
||||
mutex_unlock(&rng_mutex);
|
||||
|
||||
if (new_rng) {
|
||||
if (old_rng != new_rng)
|
||||
add_early_randomness(new_rng);
|
||||
put_rng(new_rng);
|
||||
}
|
||||
|
||||
wait_for_completion(&rng->cleanup_done);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hwrng_unregister);
|
||||
|
@@ -109,7 +109,6 @@ static int exynos_trng_init(struct hwrng *rng)
|
||||
static int exynos_trng_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct exynos_trng_dev *trng;
|
||||
struct resource *res;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
trng = devm_kzalloc(&pdev->dev, sizeof(*trng), GFP_KERNEL);
|
||||
@@ -128,8 +127,7 @@ static int exynos_trng_probe(struct platform_device *pdev)
|
||||
platform_set_drvdata(pdev, trng);
|
||||
trng->dev = &pdev->dev;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
trng->mem = devm_ioremap_resource(&pdev->dev, res);
|
||||
trng->mem = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(trng->mem))
|
||||
return PTR_ERR(trng->mem);
|
||||
|
||||
|
@@ -73,7 +73,6 @@ static int hisi_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
|
||||
static int hisi_rng_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct hisi_rng *rng;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL);
|
||||
@@ -82,8 +81,7 @@ static int hisi_rng_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, rng);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
rng->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
rng->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(rng->base))
|
||||
return PTR_ERR(rng->base);
|
||||
|
||||
|
99
drivers/char/hw_random/hisi-trng-v2.c
Arquivo normal
99
drivers/char/hw_random/hisi-trng-v2.c
Arquivo normal
@@ -0,0 +1,99 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2019 HiSilicon Limited. */
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/hw_random.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/random.h>
|
||||
|
||||
#define HISI_TRNG_REG 0x00F0
|
||||
#define HISI_TRNG_BYTES 4
|
||||
#define HISI_TRNG_QUALITY 512
|
||||
#define SLEEP_US 10
|
||||
#define TIMEOUT_US 10000
|
||||
|
||||
struct hisi_trng {
|
||||
void __iomem *base;
|
||||
struct hwrng rng;
|
||||
};
|
||||
|
||||
static int hisi_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
|
||||
{
|
||||
struct hisi_trng *trng;
|
||||
int currsize = 0;
|
||||
u32 val = 0;
|
||||
u32 ret;
|
||||
|
||||
trng = container_of(rng, struct hisi_trng, rng);
|
||||
|
||||
do {
|
||||
ret = readl_poll_timeout(trng->base + HISI_TRNG_REG, val,
|
||||
val, SLEEP_US, TIMEOUT_US);
|
||||
if (ret)
|
||||
return currsize;
|
||||
|
||||
if (max - currsize >= HISI_TRNG_BYTES) {
|
||||
memcpy(buf + currsize, &val, HISI_TRNG_BYTES);
|
||||
currsize += HISI_TRNG_BYTES;
|
||||
if (currsize == max)
|
||||
return currsize;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* copy remaining bytes */
|
||||
memcpy(buf + currsize, &val, max - currsize);
|
||||
currsize = max;
|
||||
} while (currsize < max);
|
||||
|
||||
return currsize;
|
||||
}
|
||||
|
||||
static int hisi_trng_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct hisi_trng *trng;
|
||||
int ret;
|
||||
|
||||
trng = devm_kzalloc(&pdev->dev, sizeof(*trng), GFP_KERNEL);
|
||||
if (!trng)
|
||||
return -ENOMEM;
|
||||
|
||||
trng->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(trng->base))
|
||||
return PTR_ERR(trng->base);
|
||||
|
||||
trng->rng.name = pdev->name;
|
||||
trng->rng.read = hisi_trng_read;
|
||||
trng->rng.quality = HISI_TRNG_QUALITY;
|
||||
|
||||
ret = devm_hwrng_register(&pdev->dev, &trng->rng);
|
||||
if (ret)
|
||||
dev_err(&pdev->dev, "failed to register hwrng!\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct acpi_device_id hisi_trng_acpi_match[] = {
|
||||
{ "HISI02B3", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, hisi_trng_acpi_match);
|
||||
|
||||
static struct platform_driver hisi_trng_driver = {
|
||||
.probe = hisi_trng_probe,
|
||||
.driver = {
|
||||
.name = "hisi-trng-v2",
|
||||
.acpi_match_table = ACPI_PTR(hisi_trng_acpi_match),
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(hisi_trng_driver);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Weili Qian <qianweili@huawei.com>");
|
||||
MODULE_AUTHOR("Zaibo Xu <xuzaibo@huawei.com>");
|
||||
MODULE_DESCRIPTION("HiSilicon true random number generator V2 driver");
|
@@ -181,7 +181,6 @@ static void iproc_rng200_cleanup(struct hwrng *rng)
|
||||
static int iproc_rng200_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct iproc_rng200_dev *priv;
|
||||
struct resource *res;
|
||||
struct device *dev = &pdev->dev;
|
||||
int ret;
|
||||
|
||||
@@ -190,13 +189,7 @@ static int iproc_rng200_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Map peripheral */
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(dev, "failed to get rng resources\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
priv->base = devm_ioremap_resource(dev, res);
|
||||
priv->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(priv->base)) {
|
||||
dev_err(dev, "failed to remap rng regs\n");
|
||||
return PTR_ERR(priv->base);
|
||||
|
@@ -21,6 +21,7 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/timekeeping.h>
|
||||
|
||||
#define SA_CMD_STATUS_OFS 0x8
|
||||
|
||||
@@ -84,14 +85,37 @@ struct ks_sa_rng {
|
||||
struct hwrng rng;
|
||||
struct clk *clk;
|
||||
struct regmap *regmap_cfg;
|
||||
struct trng_regs *reg_rng;
|
||||
struct trng_regs __iomem *reg_rng;
|
||||
u64 ready_ts;
|
||||
unsigned int refill_delay_ns;
|
||||
};
|
||||
|
||||
static unsigned int cycles_to_ns(unsigned long clk_rate, unsigned int cycles)
|
||||
{
|
||||
return DIV_ROUND_UP_ULL((TRNG_DEF_CLK_DIV_CYCLES + 1) * 1000000000ull *
|
||||
cycles, clk_rate);
|
||||
}
|
||||
|
||||
static unsigned int startup_delay_ns(unsigned long clk_rate)
|
||||
{
|
||||
if (!TRNG_DEF_STARTUP_CYCLES)
|
||||
return cycles_to_ns(clk_rate, BIT(24));
|
||||
return cycles_to_ns(clk_rate, 256 * TRNG_DEF_STARTUP_CYCLES);
|
||||
}
|
||||
|
||||
static unsigned int refill_delay_ns(unsigned long clk_rate)
|
||||
{
|
||||
if (!TRNG_DEF_MAX_REFILL_CYCLES)
|
||||
return cycles_to_ns(clk_rate, BIT(24));
|
||||
return cycles_to_ns(clk_rate, 256 * TRNG_DEF_MAX_REFILL_CYCLES);
|
||||
}
|
||||
|
||||
static int ks_sa_rng_init(struct hwrng *rng)
|
||||
{
|
||||
u32 value;
|
||||
struct device *dev = (struct device *)rng->priv;
|
||||
struct ks_sa_rng *ks_sa_rng = dev_get_drvdata(dev);
|
||||
unsigned long clk_rate = clk_get_rate(ks_sa_rng->clk);
|
||||
|
||||
/* Enable RNG module */
|
||||
regmap_write_bits(ks_sa_rng->regmap_cfg, SA_CMD_STATUS_OFS,
|
||||
@@ -120,6 +144,10 @@ static int ks_sa_rng_init(struct hwrng *rng)
|
||||
value |= TRNG_CNTL_REG_TRNG_ENABLE;
|
||||
writel(value, &ks_sa_rng->reg_rng->control);
|
||||
|
||||
ks_sa_rng->refill_delay_ns = refill_delay_ns(clk_rate);
|
||||
ks_sa_rng->ready_ts = ktime_get_ns() +
|
||||
startup_delay_ns(clk_rate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -144,6 +172,7 @@ static int ks_sa_rng_data_read(struct hwrng *rng, u32 *data)
|
||||
data[1] = readl(&ks_sa_rng->reg_rng->output_h);
|
||||
|
||||
writel(TRNG_INTACK_REG_READY, &ks_sa_rng->reg_rng->intack);
|
||||
ks_sa_rng->ready_ts = ktime_get_ns() + ks_sa_rng->refill_delay_ns;
|
||||
|
||||
return sizeof(u32) * 2;
|
||||
}
|
||||
@@ -152,10 +181,19 @@ static int ks_sa_rng_data_present(struct hwrng *rng, int wait)
|
||||
{
|
||||
struct device *dev = (struct device *)rng->priv;
|
||||
struct ks_sa_rng *ks_sa_rng = dev_get_drvdata(dev);
|
||||
u64 now = ktime_get_ns();
|
||||
|
||||
u32 ready;
|
||||
int j;
|
||||
|
||||
if (wait && now < ks_sa_rng->ready_ts) {
|
||||
/* Max delay expected here is 81920000 ns */
|
||||
unsigned long min_delay =
|
||||
DIV_ROUND_UP((u32)(ks_sa_rng->ready_ts - now), 1000);
|
||||
|
||||
usleep_range(min_delay, min_delay + SA_RNG_DATA_RETRY_DELAY);
|
||||
}
|
||||
|
||||
for (j = 0; j < SA_MAX_RNG_DATA_RETRIES; j++) {
|
||||
ready = readl(&ks_sa_rng->reg_rng->status);
|
||||
ready &= TRNG_STATUS_REG_READY;
|
||||
@@ -174,7 +212,6 @@ static int ks_sa_rng_probe(struct platform_device *pdev)
|
||||
struct ks_sa_rng *ks_sa_rng;
|
||||
struct device *dev = &pdev->dev;
|
||||
int ret;
|
||||
struct resource *mem;
|
||||
|
||||
ks_sa_rng = devm_kzalloc(dev, sizeof(*ks_sa_rng), GFP_KERNEL);
|
||||
if (!ks_sa_rng)
|
||||
@@ -190,8 +227,7 @@ static int ks_sa_rng_probe(struct platform_device *pdev)
|
||||
};
|
||||
ks_sa_rng->rng.priv = (unsigned long)dev;
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
ks_sa_rng->reg_rng = devm_ioremap_resource(dev, mem);
|
||||
ks_sa_rng->reg_rng = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(ks_sa_rng->reg_rng))
|
||||
return PTR_ERR(ks_sa_rng->reg_rng);
|
||||
|
||||
|
@@ -42,7 +42,6 @@ static int meson_rng_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct meson_rng_data *data;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
|
||||
@@ -51,8 +50,7 @@ static int meson_rng_probe(struct platform_device *pdev)
|
||||
|
||||
data->pdev = pdev;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
data->base = devm_ioremap_resource(dev, res);
|
||||
data->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(data->base))
|
||||
return PTR_ERR(data->base);
|
||||
|
||||
|
@@ -105,16 +105,9 @@ static int mtk_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
|
||||
|
||||
static int mtk_rng_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
int ret;
|
||||
struct mtk_rng *priv;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "no iomem resource\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
@@ -135,7 +128,7 @@ static int mtk_rng_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
priv->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
priv->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(priv->base))
|
||||
return PTR_ERR(priv->base);
|
||||
|
||||
|
184
drivers/char/hw_random/npcm-rng.c
Arquivo normal
184
drivers/char/hw_random/npcm-rng.c
Arquivo normal
@@ -0,0 +1,184 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2019 Nuvoton Technology corporation.
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/hw_random.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#define NPCM_RNGCS_REG 0x00 /* Control and status register */
|
||||
#define NPCM_RNGD_REG 0x04 /* Data register */
|
||||
#define NPCM_RNGMODE_REG 0x08 /* Mode register */
|
||||
|
||||
#define NPCM_RNG_CLK_SET_25MHZ GENMASK(4, 3) /* 20-25 MHz */
|
||||
#define NPCM_RNG_DATA_VALID BIT(1)
|
||||
#define NPCM_RNG_ENABLE BIT(0)
|
||||
#define NPCM_RNG_M1ROSEL BIT(1)
|
||||
|
||||
#define NPCM_RNG_TIMEOUT_USEC 20000
|
||||
#define NPCM_RNG_POLL_USEC 1000
|
||||
|
||||
#define to_npcm_rng(p) container_of(p, struct npcm_rng, rng)
|
||||
|
||||
struct npcm_rng {
|
||||
void __iomem *base;
|
||||
struct hwrng rng;
|
||||
};
|
||||
|
||||
static int npcm_rng_init(struct hwrng *rng)
|
||||
{
|
||||
struct npcm_rng *priv = to_npcm_rng(rng);
|
||||
|
||||
writel(NPCM_RNG_CLK_SET_25MHZ | NPCM_RNG_ENABLE,
|
||||
priv->base + NPCM_RNGCS_REG);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void npcm_rng_cleanup(struct hwrng *rng)
|
||||
{
|
||||
struct npcm_rng *priv = to_npcm_rng(rng);
|
||||
|
||||
writel(NPCM_RNG_CLK_SET_25MHZ, priv->base + NPCM_RNGCS_REG);
|
||||
}
|
||||
|
||||
static int npcm_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
|
||||
{
|
||||
struct npcm_rng *priv = to_npcm_rng(rng);
|
||||
int retval = 0;
|
||||
int ready;
|
||||
|
||||
pm_runtime_get_sync((struct device *)priv->rng.priv);
|
||||
|
||||
while (max >= sizeof(u32)) {
|
||||
if (wait) {
|
||||
if (readl_poll_timeout(priv->base + NPCM_RNGCS_REG,
|
||||
ready,
|
||||
ready & NPCM_RNG_DATA_VALID,
|
||||
NPCM_RNG_POLL_USEC,
|
||||
NPCM_RNG_TIMEOUT_USEC))
|
||||
break;
|
||||
} else {
|
||||
if ((readl(priv->base + NPCM_RNGCS_REG) &
|
||||
NPCM_RNG_DATA_VALID) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
*(u32 *)buf = readl(priv->base + NPCM_RNGD_REG);
|
||||
retval += sizeof(u32);
|
||||
buf += sizeof(u32);
|
||||
max -= sizeof(u32);
|
||||
}
|
||||
|
||||
pm_runtime_mark_last_busy((struct device *)priv->rng.priv);
|
||||
pm_runtime_put_sync_autosuspend((struct device *)priv->rng.priv);
|
||||
|
||||
return retval || !wait ? retval : -EIO;
|
||||
}
|
||||
|
||||
static int npcm_rng_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct npcm_rng *priv;
|
||||
int ret;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(priv->base))
|
||||
return PTR_ERR(priv->base);
|
||||
|
||||
dev_set_drvdata(&pdev->dev, priv);
|
||||
pm_runtime_set_autosuspend_delay(&pdev->dev, 100);
|
||||
pm_runtime_use_autosuspend(&pdev->dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
#ifndef CONFIG_PM
|
||||
priv->rng.init = npcm_rng_init;
|
||||
priv->rng.cleanup = npcm_rng_cleanup;
|
||||
#endif
|
||||
priv->rng.name = pdev->name;
|
||||
priv->rng.read = npcm_rng_read;
|
||||
priv->rng.priv = (unsigned long)&pdev->dev;
|
||||
priv->rng.quality = 1000;
|
||||
|
||||
writel(NPCM_RNG_M1ROSEL, priv->base + NPCM_RNGMODE_REG);
|
||||
|
||||
ret = devm_hwrng_register(&pdev->dev, &priv->rng);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to register rng device: %d\n",
|
||||
ret);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int npcm_rng_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct npcm_rng *priv = platform_get_drvdata(pdev);
|
||||
|
||||
devm_hwrng_unregister(&pdev->dev, &priv->rng);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int npcm_rng_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct npcm_rng *priv = dev_get_drvdata(dev);
|
||||
|
||||
npcm_rng_cleanup(&priv->rng);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int npcm_rng_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct npcm_rng *priv = dev_get_drvdata(dev);
|
||||
|
||||
return npcm_rng_init(&priv->rng);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops npcm_rng_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(npcm_rng_runtime_suspend,
|
||||
npcm_rng_runtime_resume, NULL)
|
||||
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||
pm_runtime_force_resume)
|
||||
};
|
||||
|
||||
static const struct of_device_id rng_dt_id[] = {
|
||||
{ .compatible = "nuvoton,npcm750-rng", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rng_dt_id);
|
||||
|
||||
static struct platform_driver npcm_rng_driver = {
|
||||
.driver = {
|
||||
.name = "npcm-rng",
|
||||
.pm = &npcm_rng_pm_ops,
|
||||
.of_match_table = of_match_ptr(rng_dt_id),
|
||||
},
|
||||
.probe = npcm_rng_probe,
|
||||
.remove = npcm_rng_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(npcm_rng_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Nuvoton NPCM Random Number Generator Driver");
|
||||
MODULE_AUTHOR("Tomer Maimon <tomer.maimon@nuvoton.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
@@ -66,6 +66,13 @@
|
||||
#define OMAP4_RNG_OUTPUT_SIZE 0x8
|
||||
#define EIP76_RNG_OUTPUT_SIZE 0x10
|
||||
|
||||
/*
|
||||
* EIP76 RNG takes approx. 700us to produce 16 bytes of output data
|
||||
* as per testing results. And to account for the lack of udelay()'s
|
||||
* reliability, we keep the timeout as 1000us.
|
||||
*/
|
||||
#define RNG_DATA_FILL_TIMEOUT 100
|
||||
|
||||
enum {
|
||||
RNG_OUTPUT_0_REG = 0,
|
||||
RNG_OUTPUT_1_REG,
|
||||
@@ -176,7 +183,7 @@ static int omap_rng_do_read(struct hwrng *rng, void *data, size_t max,
|
||||
if (max < priv->pdata->data_size)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < 20; i++) {
|
||||
for (i = 0; i < RNG_DATA_FILL_TIMEOUT; i++) {
|
||||
present = priv->pdata->data_present(priv);
|
||||
if (present || !wait)
|
||||
break;
|
||||
@@ -432,7 +439,6 @@ static int get_omap_rng_device_details(struct omap_rng_dev *omap_rng)
|
||||
static int omap_rng_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_rng_dev *priv;
|
||||
struct resource *res;
|
||||
struct device *dev = &pdev->dev;
|
||||
int ret;
|
||||
|
||||
@@ -449,8 +455,7 @@ static int omap_rng_probe(struct platform_device *pdev)
|
||||
platform_set_drvdata(pdev, priv);
|
||||
priv->dev = dev;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
priv->base = devm_ioremap_resource(dev, res);
|
||||
priv->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(priv->base)) {
|
||||
ret = PTR_ERR(priv->base);
|
||||
goto err_ioremap;
|
||||
|
@@ -11,8 +11,6 @@
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/random.h>
|
||||
@@ -20,117 +18,159 @@
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#define RNG_RESET 0x01
|
||||
#define RNG_GEN_PRNG_HW_INIT 0x02
|
||||
#define RNG_GEN_HW 0x08
|
||||
|
||||
/* param1: ptr, param2: count, param3: flag */
|
||||
static u32 (*omap3_rom_rng_call)(u32, u32, u32);
|
||||
|
||||
static struct delayed_work idle_work;
|
||||
static int rng_idle;
|
||||
static struct clk *rng_clk;
|
||||
|
||||
static void omap3_rom_rng_idle(struct work_struct *work)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = omap3_rom_rng_call(0, 0, RNG_RESET);
|
||||
if (r != 0) {
|
||||
pr_err("reset failed: %d\n", r);
|
||||
return;
|
||||
}
|
||||
clk_disable_unprepare(rng_clk);
|
||||
rng_idle = 1;
|
||||
}
|
||||
|
||||
static int omap3_rom_rng_get_random(void *buf, unsigned int count)
|
||||
{
|
||||
u32 r;
|
||||
u32 ptr;
|
||||
|
||||
cancel_delayed_work_sync(&idle_work);
|
||||
if (rng_idle) {
|
||||
r = clk_prepare_enable(rng_clk);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = omap3_rom_rng_call(0, 0, RNG_GEN_PRNG_HW_INIT);
|
||||
if (r != 0) {
|
||||
clk_disable_unprepare(rng_clk);
|
||||
pr_err("HW init failed: %d\n", r);
|
||||
return -EIO;
|
||||
}
|
||||
rng_idle = 0;
|
||||
}
|
||||
|
||||
ptr = virt_to_phys(buf);
|
||||
r = omap3_rom_rng_call(ptr, count, RNG_GEN_HW);
|
||||
schedule_delayed_work(&idle_work, msecs_to_jiffies(500));
|
||||
if (r != 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
struct omap_rom_rng {
|
||||
struct clk *clk;
|
||||
struct device *dev;
|
||||
struct hwrng ops;
|
||||
u32 (*rom_rng_call)(u32 ptr, u32 count, u32 flag);
|
||||
};
|
||||
|
||||
static int omap3_rom_rng_read(struct hwrng *rng, void *data, size_t max, bool w)
|
||||
{
|
||||
struct omap_rom_rng *ddata;
|
||||
u32 ptr;
|
||||
int r;
|
||||
|
||||
r = omap3_rom_rng_get_random(data, 4);
|
||||
if (r < 0)
|
||||
ddata = (struct omap_rom_rng *)rng->priv;
|
||||
|
||||
r = pm_runtime_get_sync(ddata->dev);
|
||||
if (r < 0) {
|
||||
pm_runtime_put_noidle(ddata->dev);
|
||||
|
||||
return r;
|
||||
return 4;
|
||||
}
|
||||
|
||||
ptr = virt_to_phys(data);
|
||||
r = ddata->rom_rng_call(ptr, 4, RNG_GEN_HW);
|
||||
if (r != 0)
|
||||
r = -EINVAL;
|
||||
else
|
||||
r = 4;
|
||||
|
||||
pm_runtime_mark_last_busy(ddata->dev);
|
||||
pm_runtime_put_autosuspend(ddata->dev);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static struct hwrng omap3_rom_rng_ops = {
|
||||
.name = "omap3-rom",
|
||||
.read = omap3_rom_rng_read,
|
||||
};
|
||||
static int __maybe_unused omap_rom_rng_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct omap_rom_rng *ddata;
|
||||
int r;
|
||||
|
||||
ddata = dev_get_drvdata(dev);
|
||||
|
||||
r = ddata->rom_rng_call(0, 0, RNG_RESET);
|
||||
if (r != 0)
|
||||
dev_err(dev, "reset failed: %d\n", r);
|
||||
|
||||
clk_disable_unprepare(ddata->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused omap_rom_rng_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct omap_rom_rng *ddata;
|
||||
int r;
|
||||
|
||||
ddata = dev_get_drvdata(dev);
|
||||
|
||||
r = clk_prepare_enable(ddata->clk);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = ddata->rom_rng_call(0, 0, RNG_GEN_PRNG_HW_INIT);
|
||||
if (r != 0) {
|
||||
clk_disable(ddata->clk);
|
||||
dev_err(dev, "HW init failed: %d\n", r);
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void omap_rom_rng_finish(void *data)
|
||||
{
|
||||
struct omap_rom_rng *ddata = data;
|
||||
|
||||
pm_runtime_dont_use_autosuspend(ddata->dev);
|
||||
pm_runtime_disable(ddata->dev);
|
||||
}
|
||||
|
||||
static int omap3_rom_rng_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_rom_rng *ddata;
|
||||
int ret = 0;
|
||||
|
||||
pr_info("initializing\n");
|
||||
ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
|
||||
if (!ddata)
|
||||
return -ENOMEM;
|
||||
|
||||
omap3_rom_rng_call = pdev->dev.platform_data;
|
||||
if (!omap3_rom_rng_call) {
|
||||
pr_err("omap3_rom_rng_call is NULL\n");
|
||||
ddata->dev = &pdev->dev;
|
||||
ddata->ops.priv = (unsigned long)ddata;
|
||||
ddata->ops.name = "omap3-rom";
|
||||
ddata->ops.read = of_device_get_match_data(&pdev->dev);
|
||||
ddata->ops.quality = 900;
|
||||
if (!ddata->ops.read) {
|
||||
dev_err(&pdev->dev, "missing rom code handler\n");
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
dev_set_drvdata(ddata->dev, ddata);
|
||||
|
||||
ddata->rom_rng_call = pdev->dev.platform_data;
|
||||
if (!ddata->rom_rng_call) {
|
||||
dev_err(ddata->dev, "rom_rng_call is NULL\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
INIT_DELAYED_WORK(&idle_work, omap3_rom_rng_idle);
|
||||
rng_clk = devm_clk_get(&pdev->dev, "ick");
|
||||
if (IS_ERR(rng_clk)) {
|
||||
pr_err("unable to get RNG clock\n");
|
||||
return PTR_ERR(rng_clk);
|
||||
ddata->clk = devm_clk_get(ddata->dev, "ick");
|
||||
if (IS_ERR(ddata->clk)) {
|
||||
dev_err(ddata->dev, "unable to get RNG clock\n");
|
||||
return PTR_ERR(ddata->clk);
|
||||
}
|
||||
|
||||
/* Leave the RNG in reset state. */
|
||||
ret = clk_prepare_enable(rng_clk);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
pm_runtime_set_autosuspend_delay(&pdev->dev, 500);
|
||||
pm_runtime_use_autosuspend(&pdev->dev);
|
||||
|
||||
ret = devm_add_action_or_reset(ddata->dev, omap_rom_rng_finish,
|
||||
ddata);
|
||||
if (ret)
|
||||
return ret;
|
||||
omap3_rom_rng_idle(0);
|
||||
|
||||
return hwrng_register(&omap3_rom_rng_ops);
|
||||
return devm_hwrng_register(ddata->dev, &ddata->ops);
|
||||
}
|
||||
|
||||
static int omap3_rom_rng_remove(struct platform_device *pdev)
|
||||
{
|
||||
cancel_delayed_work_sync(&idle_work);
|
||||
hwrng_unregister(&omap3_rom_rng_ops);
|
||||
clk_disable_unprepare(rng_clk);
|
||||
return 0;
|
||||
}
|
||||
static const struct of_device_id omap_rom_rng_match[] = {
|
||||
{ .compatible = "nokia,n900-rom-rng", .data = omap3_rom_rng_read, },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, omap_rom_rng_match);
|
||||
|
||||
static const struct dev_pm_ops omap_rom_rng_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(omap_rom_rng_runtime_suspend,
|
||||
omap_rom_rng_runtime_resume)
|
||||
};
|
||||
|
||||
static struct platform_driver omap3_rom_rng_driver = {
|
||||
.driver = {
|
||||
.name = "omap3-rom-rng",
|
||||
.of_match_table = omap_rom_rng_match,
|
||||
.pm = &omap_rom_rng_pm_ops,
|
||||
},
|
||||
.probe = omap3_rom_rng_probe,
|
||||
.remove = omap3_rom_rng_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(omap3_rom_rng_driver);
|
||||
|
@@ -86,10 +86,8 @@ static struct hwrng pasemi_rng = {
|
||||
static int rng_probe(struct platform_device *pdev)
|
||||
{
|
||||
void __iomem *rng_regs;
|
||||
struct resource *res;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
rng_regs = devm_ioremap_resource(&pdev->dev, res);
|
||||
rng_regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(rng_regs))
|
||||
return PTR_ERR(rng_regs);
|
||||
|
||||
|
@@ -70,7 +70,6 @@ static int pic32_rng_read(struct hwrng *rng, void *buf, size_t max,
|
||||
static int pic32_rng_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pic32_rng *priv;
|
||||
struct resource *res;
|
||||
u32 v;
|
||||
int ret;
|
||||
|
||||
@@ -78,8 +77,7 @@ static int pic32_rng_probe(struct platform_device *pdev)
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
priv->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
priv->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(priv->base))
|
||||
return PTR_ERR(priv->base);
|
||||
|
||||
|
@@ -72,7 +72,6 @@ static int st_rng_read(struct hwrng *rng, void *data, size_t max, bool wait)
|
||||
static int st_rng_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct st_rng_data *ddata;
|
||||
struct resource *res;
|
||||
struct clk *clk;
|
||||
void __iomem *base;
|
||||
int ret;
|
||||
@@ -81,8 +80,7 @@ static int st_rng_probe(struct platform_device *pdev)
|
||||
if (!ddata)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(&pdev->dev, res);
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
|
@@ -107,14 +107,12 @@ static int tx4939_rng_data_read(struct hwrng *rng, u32 *buffer)
|
||||
static int __init tx4939_rng_probe(struct platform_device *dev)
|
||||
{
|
||||
struct tx4939_rng *rngdev;
|
||||
struct resource *r;
|
||||
int i;
|
||||
|
||||
rngdev = devm_kzalloc(&dev->dev, sizeof(*rngdev), GFP_KERNEL);
|
||||
if (!rngdev)
|
||||
return -ENOMEM;
|
||||
r = platform_get_resource(dev, IORESOURCE_MEM, 0);
|
||||
rngdev->base = devm_ioremap_resource(&dev->dev, r);
|
||||
rngdev->base = devm_platform_ioremap_resource(dev, 0);
|
||||
if (IS_ERR(rngdev->base))
|
||||
return PTR_ERR(rngdev->base);
|
||||
|
||||
|
@@ -313,7 +313,6 @@ static struct hwrng xgene_rng_func = {
|
||||
|
||||
static int xgene_rng_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
struct xgene_rng_dev *ctx;
|
||||
int rc = 0;
|
||||
|
||||
@@ -324,8 +323,7 @@ static int xgene_rng_probe(struct platform_device *pdev)
|
||||
ctx->dev = &pdev->dev;
|
||||
platform_set_drvdata(pdev, ctx);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
ctx->csr_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
ctx->csr_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(ctx->csr_base))
|
||||
return PTR_ERR(ctx->csr_base);
|
||||
|
||||
|
Referência em uma nova issue
Block a user