From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753203AbdLVNX6 (ORCPT ); Fri, 22 Dec 2017 08:23:58 -0500 Received: from mailout1.w1.samsung.com ([210.118.77.11]:47903 "EHLO mailout1.w1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751537AbdLVNXx (ORCPT ); Fri, 22 Dec 2017 08:23:53 -0500 DKIM-Filter: OpenDKIM Filter v2.11.0 mailout1.w1.samsung.com 20171222132350euoutp01fc2e885d399ca33a6213187dbc15183c~CoJ9P4UWA0779707797euoutp01u X-AuditID: cbfec7f2-f793b6d000003243-ae-5a3d076555e2 MIME-version: 1.0 Content-transfer-encoding: 8BIT Content-type: text/plain; charset="UTF-8" From: =?UTF-8?q?=C5=81ukasz=20Stelmach?= To: "Andrew F . Davis" , PrasannaKumar Muralidharan , Rob Herring , Matt Mackall , Herbert Xu , Krzysztof Kozlowski , Kukjin Kim , devicetree@vger.kernel.org, linux-crypto@vger.kernel.org, linux-samsung-soc@vger.kernel.org, linux-kernel@vger.kernel.org Cc: =?UTF-8?q?=C5=81ukasz=20Stelmach?= , Marek Szyprowski , Bartlomiej Zolnierkiewicz Subject: [PATCH v4] hwrng: exynos - add Samsung Exynos True RNG driver Date: Fri, 22 Dec 2017 14:23:38 +0100 Message-id: <20171222132338.30054-1-l.stelmach@samsung.com> X-Mailer: git-send-email 2.11.0 In-reply-to: <20171204125351.26805-3-l.stelmach@samsung.com> Organization: Samsung R&D Institute Poland X-Brightmail-Tracker: H4sIAAAAAAAAA01Sa0hTYRjuO+ds57icfU2rFy2tgYhjmV2og9NQSD0/tIJ+NSgdedBoXth0 ZFRIkDk1dRkm66KhhkjhBZ13yTl0Kbq0wryWCFEaWqmlEJLbUfLf873P8z7v+z58DClrF3kz V1PSeV2KRisXSyhL79rQYZ4OUwebBlTsYr+JZutLa0VsmW1IxObN7WcLZ+dJ1uGoo9kxazVi P02vEey7tidittTRRbCvbFM0W24pQGxVYR9i73ba6HAPrtU8RXOW1/5cQ41RzBU01iCu4Fsd 4vo+NhPcUoPveVotCU3gtVcNvO7I6XhJ0tPZnWk93PUPxnuiLNSiykVuDOAT8HSwRyzgvfB2 unYDSxgZrkJQb3opEh5LCMa6F8VbHTMTdZvECwTLd4pETkKKd8Nq8TSVixiGxH5gG7nmLJM4 EJraa2lBv4ygpKsZOQkxjoDCKrvLyAsXkzDZseBSkU7Xbssb1zhPHAWmjnzSiSnsDxN3fxPO CVKsglGHj7CRH7RlD7uWcMOhsNxc5pLvwgp4eWeUcnoCLqZh5fMrWmg4A+MzTygBe8JcX+Nm fT8Yc7oJoaEQQU/Zn03iIYKK5+ECVsHfGpNYuM0DHlgekc6FAEshJ1smQA4qRkBQR0Db+2eb aW1YTv4YJIqQn3lbYOb/gZm3BVaOyBrkxWfokxN5/fEgvSZZn5GSGHQlNbkBbXypgfW+Xy1o xR5iRZhBcndpXatKLRNpDPrMZCsChpR7SQ32ULVMmqDJvMHrUuN0GVpeb0U+DCXfJw1TZ1+U 4URNOn+N59N43RZLMG7eWejU2EFeGZTjdVsZGxl2Iern19l+ekf7cePjfs/ByAHfcYIIWE9T 7EkKuvUlL27YogwkK1cvf89Pjy3pNMecq+x0H1q4d1Ox3vv9JKWyKIdj4lLORmvxYk69Yoyy G5culRjsO+eDmx4WS5TkQjxl/x2iPrAWdz966dCa9Vh1wE05pU/SHFWQOr3mH74zE2FOAwAA X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFprAIsWRmVeSWpSXmKPExsVy+t/xK7qp7LZRBufusVi8PzWR3WLjjPWs FvOPnGO16H4lY9H/+DWzxfnzG9gtbh5awWhx/95PJovLu+awWcw4v4/JYu2Ru+wWC7b1MVos 7T/OaNG69wi7A5/Hzll32T22HVD12LSqk82jb8sqRo++lxsYPY7f2M7k8XmTXAB7FJdNSmpO Zllqkb5dAlfG3MfcBYc9Kq52trM2MO6w7mLk5JAQMJF4eHsDK4QtJnHh3nq2LkYuDiGBJYwS U/rfgiV4BQQlfky+x9LFyMHBLCAvceRSNkiYWUBdYtK8RcwQ9d8YJd4vmw5WzybgKNG/9AQr SEJEYCqzxP+2LjCHWWAZo8SfnlY2kCphATeJiXt6mEFsFgFVidut35hANvAKWEtcPy8NcZG8 xK62i2BDOQVsJL5snw9WLgRU0tk8nQnE5hfQkljTdJ1lAqPgLCS3zkK4dRaSWxcwMq9iFEkt Lc5Nzy021CtOzC0uzUvXS87P3cQIjKdtx35u3sF4aWPwIUYBDkYlHt4NO62jhFgTy4orcw8x SnAwK4nwlp2wiRLiTUmsrEotyo8vKs1JLT7EKM3BoiTO27tndaSQQHpiSWp2ampBahFMlomD U6qBUT3pvajJrGdNJZNjv+tdDE5kWKdvfiZvYz77+q16BkU7yyZKZcxoONLQnvlddfLd/8kn 1qsam0yTevIqbMth4wnPz5T4SriKzHJOWHK8/+6U1YE7zBZdfVcz7dIjV7PMuMMlgZ0qHBaz 3ymKbnj5t9GMbXKuPc+zdapbzf4GbPFhrPj04pT0XyWW4oxEQy3mouJEAHuRUo+jAgAA X-CMS-MailID: 20171222132349eucas1p2270e45b81c9d77cb09addfd769877098 X-Msg-Generator: CA CMS-TYPE: 201P X-CMS-RootMailID: 20171222132349eucas1p2270e45b81c9d77cb09addfd769877098 X-RootMTR: 20171222132349eucas1p2270e45b81c9d77cb09addfd769877098 References: <20171204125351.26805-3-l.stelmach@samsung.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add support for True Random Number Generator found in Samsung Exynos 5250+ SoCs. Signed-off-by: Łukasz Stelmach Reviewed-by: Krzysztof Kozlowski --- Changes since v3: - Fixed typo in the secongd argument of MODULE_DEVICE_TABLE (Thanks, Herbert Xu) MAINTAINERS | 7 + drivers/char/hw_random/Kconfig | 12 ++ drivers/char/hw_random/Makefile | 1 + drivers/char/hw_random/exynos-trng.c | 245 +++++++++++++++++++++++++++++++++++ 4 files changed, 265 insertions(+) create mode 100644 drivers/char/hw_random/exynos-trng.c diff --git a/MAINTAINERS b/MAINTAINERS index e6d849d0d153..1082846edb9b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11933,6 +11933,13 @@ S: Maintained F: drivers/crypto/exynos-rng.c F: Documentation/devicetree/bindings/crypto/samsung,exynos-rng4.txt +SAMSUNG EXYNOS TRUE RANDOM NUMBER GENERATOR (TRNG) DRIVER +M: Łukasz Stelmach +L: linux-samsung-soc@vger.kernel.org +S: Maintained +F: drivers/char/hw_random/exynos-trng.c +F: Documentation/devicetree/bindings/rng/samsung,exynos5250-trng.txt + SAMSUNG FRAMEBUFFER DRIVER M: Jingoo Han L: linux-fbdev@vger.kernel.org diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 90e4bb24819e..32f715394904 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -437,6 +437,18 @@ config HW_RANDOM_S390 If unsure, say Y. +config HW_RANDOM_EXYNOS + tristate "Samsung Exynos True Random Number Generator support" + depends on ARCH_EXYNOS || COMPILE_TEST + default HW_RANDOM + ---help--- + This driver provides support for the True Random Number + Generator available in Exynos SoCs. + + To compile this driver as a module, choose M here: the module + will be called exynos-trng. + + If unsure, say Y. endif # HW_RANDOM config UML_RANDOM diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index e7146a84d44a..7c8a66fe8cf6 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o obj-$(CONFIG_HW_RANDOM_N2RNG) += n2-rng.o n2-rng-y := n2-drv.o n2-asm.o obj-$(CONFIG_HW_RANDOM_VIA) += via-rng.o +obj-$(CONFIG_HW_RANDOM_EXYNOS) += exynos-trng.o obj-$(CONFIG_HW_RANDOM_IXP4XX) += ixp4xx-rng.o obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o obj-$(CONFIG_HW_RANDOM_OMAP3_ROM) += omap3-rom-rng.o diff --git a/drivers/char/hw_random/exynos-trng.c b/drivers/char/hw_random/exynos-trng.c new file mode 100644 index 000000000000..175708f9aa1d --- /dev/null +++ b/drivers/char/hw_random/exynos-trng.c @@ -0,0 +1,245 @@ +/* + * RNG driver for Exynos TRNGs + * + * Author: Łukasz Stelmach + * + * Copyright 2017 (c) Samsung Electronics Software, Inc. + * + * Based on the Exynos PRNG driver drivers/crypto/exynos-rng by + * Krzysztof Kozłowski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define EXYNOS_TRNG_CLKDIV (0x0) + +#define EXYNOS_TRNG_CTRL (0x20) +#define EXYNOS_TRNG_CTRL_RNGEN BIT(31) + +#define EXYNOS_TRNG_POST_CTRL (0x30) +#define EXYNOS_TRNG_ONLINE_CTRL (0x40) +#define EXYNOS_TRNG_ONLINE_STAT (0x44) +#define EXYNOS_TRNG_ONLINE_MAXCHI2 (0x48) +#define EXYNOS_TRNG_FIFO_CTRL (0x50) +#define EXYNOS_TRNG_FIFO_0 (0x80) +#define EXYNOS_TRNG_FIFO_1 (0x84) +#define EXYNOS_TRNG_FIFO_2 (0x88) +#define EXYNOS_TRNG_FIFO_3 (0x8c) +#define EXYNOS_TRNG_FIFO_4 (0x90) +#define EXYNOS_TRNG_FIFO_5 (0x94) +#define EXYNOS_TRNG_FIFO_6 (0x98) +#define EXYNOS_TRNG_FIFO_7 (0x9c) +#define EXYNOS_TRNG_FIFO_LEN (8) +#define EXYNOS_TRNG_CLOCK_RATE (500000) + + +struct exynos_trng_dev { + struct device *dev; + void __iomem *mem; + struct clk *clk; + struct hwrng rng; +}; + +static int exynos_trng_do_read(struct hwrng *rng, void *data, size_t max, + bool wait) +{ + struct exynos_trng_dev *trng; + u32 val; + + max = min_t(size_t, max, (EXYNOS_TRNG_FIFO_LEN * 4)); + + trng = (struct exynos_trng_dev *)rng->priv; + + writel_relaxed(max * 8, trng->mem + EXYNOS_TRNG_FIFO_CTRL); + val = readl_poll_timeout(trng->mem + EXYNOS_TRNG_FIFO_CTRL, val, + val == 0, 200, 1000000); + if (val < 0) + return val; + + memcpy_fromio(data, trng->mem + EXYNOS_TRNG_FIFO_0, max); + + return max; +} + +static int exynos_trng_init(struct hwrng *rng) +{ + struct exynos_trng_dev *trng = (struct exynos_trng_dev *)rng->priv; + unsigned long sss_rate; + u32 val; + + sss_rate = clk_get_rate(trng->clk); + + /* + * For most TRNG circuits the clock frequency of under 500 kHz + * is safe. + */ + val = sss_rate / (EXYNOS_TRNG_CLOCK_RATE * 2); + if (val > 0x7fff) { + dev_err(trng->dev, "clock divider too large: %d", val); + return -ERANGE; + } + val = val << 1; + writel_relaxed(val, trng->mem + EXYNOS_TRNG_CLKDIV); + + /* Enable the generator. */ + val = EXYNOS_TRNG_CTRL_RNGEN; + writel_relaxed(val, trng->mem + EXYNOS_TRNG_CTRL); + + /* + * Disable post-processing. /dev/hwrng is supposed to deliver + * unprocessed data. + */ + writel_relaxed(0, trng->mem + EXYNOS_TRNG_POST_CTRL); + + return 0; +} + +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); + if (!trng) + return ret; + + trng->rng.name = devm_kstrdup(&pdev->dev, dev_name(&pdev->dev), + GFP_KERNEL); + if (!trng->rng.name) + return ret; + + trng->rng.init = exynos_trng_init; + trng->rng.read = exynos_trng_do_read; + trng->rng.priv = (unsigned long) trng; + + 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); + if (IS_ERR(trng->mem)) { + dev_err(&pdev->dev, "Could not map IO resources.\n"); + return PTR_ERR(trng->mem); + } + + pm_runtime_enable(&pdev->dev); + ret = pm_runtime_get_sync(&pdev->dev); + if (ret < 0) { + dev_err(&pdev->dev, "Could not get runtime PM.\n"); + goto err_pm_get; + } + + trng->clk = devm_clk_get(&pdev->dev, "secss"); + if (IS_ERR(trng->clk)) { + ret = PTR_ERR(trng->clk); + dev_err(&pdev->dev, "Could not get clock.\n"); + goto err_clock; + } + + ret = clk_prepare_enable(trng->clk); + if (ret) { + dev_err(&pdev->dev, "Could not enable the clk.\n"); + goto err_clock; + } + + ret = hwrng_register(&trng->rng); + if (ret) { + dev_err(&pdev->dev, "Could not register hwrng device.\n"); + goto err_register; + } + + dev_info(&pdev->dev, "Exynos True Random Number Generator.\n"); + + return 0; + +err_register: + clk_disable_unprepare(trng->clk); + +err_clock: + pm_runtime_put_sync(&pdev->dev); + +err_pm_get: + pm_runtime_disable(&pdev->dev); + + return ret; +} + +static int exynos_trng_remove(struct platform_device *pdev) +{ + struct exynos_trng_dev *trng = platform_get_drvdata(pdev); + + hwrng_unregister(&trng->rng); + clk_disable_unprepare(trng->clk); + + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static int __maybe_unused exynos_trng_suspend(struct device *dev) +{ + pm_runtime_put_sync(dev); + + return 0; +} + +static int __maybe_unused exynos_trng_resume(struct device *dev) +{ + int ret; + + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + dev_err(dev, "Could not get runtime PM.\n"); + pm_runtime_put_noidle(dev); + return ret; + } + + return 0; +} + +static SIMPLE_DEV_PM_OPS(exynos_trng_pm_ops, exynos_trng_suspend, + exynos_trng_resume); + +static const struct of_device_id exynos_trng_dt_match[] = { + { + .compatible = "samsung,exynos5250-trng", + }, + { }, +}; +MODULE_DEVICE_TABLE(of, exynos_trng_dt_match); + +static struct platform_driver exynos_trng_driver = { + .driver = { + .name = "exynos-trng", + .pm = &exynos_trng_pm_ops, + .of_match_table = exynos_trng_dt_match, + }, + .probe = exynos_trng_probe, + .remove = exynos_trng_remove, +}; + +module_platform_driver(exynos_trng_driver); +MODULE_AUTHOR("Łukasz Stelmach"); +MODULE_DESCRIPTION("H/W TRNG driver for Exynos chips"); +MODULE_LICENSE("GPL"); -- 2.11.0