From patchwork Thu Nov 23 15:09:13 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Lukasz Stelmach X-Patchwork-Id: 10072975 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id CA70660353 for ; Thu, 23 Nov 2017 15:11:08 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B80BE2A111 for ; Thu, 23 Nov 2017 15:11:08 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id ACADE2A117; Thu, 23 Nov 2017 15:11:08 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1004B2A11D for ; Thu, 23 Nov 2017 15:11:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752874AbdKWPKl (ORCPT ); Thu, 23 Nov 2017 10:10:41 -0500 Received: from mailout1.w1.samsung.com ([210.118.77.11]:33660 "EHLO mailout1.w1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752643AbdKWPKL (ORCPT ); Thu, 23 Nov 2017 10:10:11 -0500 Received: from eucas1p2.samsung.com (unknown [182.198.249.207]) by mailout1.w1.samsung.com (KnoxPortal) with ESMTP id 20171123151008euoutp01fd3a63409734d19b6cd454fa786ebd77~5v5fTPoFX1839818398euoutp011; Thu, 23 Nov 2017 15:10:08 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout1.w1.samsung.com 20171123151008euoutp01fd3a63409734d19b6cd454fa786ebd77~5v5fTPoFX1839818398euoutp011 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1511449808; bh=dR76DsEbTDQ3q0gcnZNSV3vTg7ACXh1vx1Fo3A9JLVc=; h=From:To:Cc:Subject:Date:In-reply-to:References:From; b=Y42zBJHtHUwQH9LV0eNAIBMpsRowDWZno1riZ7oDCCU+/pVLsu0ylj4FAMWUudC/H RRs1yO9Wh5dHJOAOBTvL/MBQiwrFLkdcKOgVhMOA9tOYkPPXQ7/0OA9qdkAj2ps1TY BbPNPSwSJMaNyR2dWNme8c1EYeX7n8ha9Q5+QYkk= Received: from eusmges2.samsung.com (unknown [203.254.199.241]) by eucas1p2.samsung.com (KnoxPortal) with ESMTP id 20171123151008eucas1p2173eac29adc8afe1b46d3021354ba12d~5v5epCXT22497324973eucas1p2n; Thu, 23 Nov 2017 15:10:08 +0000 (GMT) Received: from eucas1p1.samsung.com ( [182.198.249.206]) by eusmges2.samsung.com (EUCPMTA) with SMTP id 88.FA.12907.FC4E61A5; Thu, 23 Nov 2017 15:10:07 +0000 (GMT) Received: from eusmgms2.samsung.com (unknown [182.198.249.180]) by eucas1p1.samsung.com (KnoxPortal) with ESMTP id 20171123151007eucas1p1cb231b31169771df3f9d57e515057413~5v5d5r43y0684306843eucas1p1R; Thu, 23 Nov 2017 15:10:07 +0000 (GMT) X-AuditID: cbfec7f1-f793a6d00000326b-71-5a16e4cffc2a Received: from eusync1.samsung.com ( [203.254.199.211]) by eusmgms2.samsung.com (EUCPMTA) with SMTP id DE.D3.20118.FC4E61A5; Thu, 23 Nov 2017 15:10:07 +0000 (GMT) MIME-version: 1.0 Content-transfer-encoding: 8BIT Content-type: text/plain; charset="UTF-8" Received: from localhost ([106.116.147.110]) by eusync1.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTPA id <0OZV00MTJM4UWH80@eusync1.samsung.com>; Thu, 23 Nov 2017 15:10:07 +0000 (GMT) From: =?UTF-8?q?=C5=81ukasz=20Stelmach?= To: Rob Herring , Matt Mackall , Herbert Xu , Krzysztof Kozlowski , devicetree@vger.kernel.org, linux-crypto@vger.kernel.org, linux-samsung-soc@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Marek Szyprowski , Bartlomiej Zolnierkiewicz , =?UTF-8?q?=C5=81ukasz=20Stelmach?= Subject: [PATCH 2/3] hwrng: exynos - add Samsung Exynos True RNG driver Date: Thu, 23 Nov 2017 16:09:13 +0100 Message-id: <20171123150914.31462-3-l.stelmach@samsung.com> X-Mailer: git-send-email 2.11.0 In-reply-to: <20171123150914.31462-1-l.stelmach@samsung.com> Organization: Samsung R&D Institute Poland X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFlrMKsWRmVeSWpSXmKPExsWy7djPc7rnn4hFGdy6q2+xccZ6Vov5R86x WnS/krE4f34Du8XNQysYLe7f+8lkcXnXHDaLGef3MVmsPXKX3WLBtj5Gi9a9R9gduD22HVD1 2LSqk82jb8sqRo++lxsYPT5vkgtgjeKySUnNySxLLdK3S+DK6F58gr1gnVfFkUs/GBsYL9p0 MXJwSAiYSNxZFtTFyAlkiklcuLeerYuRi0NIYCmjRPuXTijnM6PEv9aPTBBVJhKt59czg9hC AssYJd4tEACxeQUEJX5MvscCMpRZQF7iyKVskDCzgKbE1t3r2SHmfGGUaH5xih0kwSbgKNG/ 9AQrSEJEYBqTxIvlq8C2MYMMXXZ4G9gGYQF3if07njCC2CwCqhIrV69mgthmLXG5ey3URfIS u9ousoLYnAI2Eh/7e8FsfgEtiTVN11lAhkoIvGaTWHf0OztEg4tE70WIFyQEhCVeHd8CFZeR uDy5G6qhn1Hi8HyYhimMEosXOkDY1hJ/Vk1kg3iOT2LStunMkIDklehoE4Io8ZD492YlVKuj ROeLt4wQ/wPNfN15h3UCo/wspCCbhQiyWUhBtoCReRWjSGppcW56arGRXnFibnFpXrpecn7u JkZg0jn97/jHHYzvT1gdYhTgYFTi4ZV4IBYlxJpYVlyZe4hRgoNZSYSX5TFQiDclsbIqtSg/ vqg0J7X4EKM0B4uSOK9tVFukkEB6YklqdmpqQWoRTJaJg1OqgfFg0HnR2GUzww12cP992SS7 efO6j+ce7j5j/vX2yt3O7HuDrtzN8zEr4tn9wPFPZ+IO04JNwnnTjbL+HWD95ta0UXCXTrzx 2TNxP3KF3y9bz/HjjUDs+glTTLln5dizJ23cYfGiZMaV6S+i/tb2fFy+uto/3uP99Gflqx8l nub88efUlsRJx+oNlViKMxINtZiLihMBqwPUQDYDAAA= X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFvrBLMWRmVeSWpSXmKPExsVy+t/xy7rnn4hFGSxawGexccZ6Vov5R86x WnS/krE4f34Du8XNQysYLe7f+8lkcXnXHDaLGef3MVmsPXKX3WLBtj5Gi9a9R9gduD22HVD1 2LSqk82jb8sqRo++lxsYPT5vkgtgjeKySUnNySxLLdK3S+DK6F58gr1gnVfFkUs/GBsYL9p0 MXJySAiYSLSeX88MYYtJXLi3nq2LkYtDSGAJo8SPVesZQRK8AoISPybfY+li5OBgFpCXOHIp GyTMLKAuMWneImaI+m+MEq0HZ7GAJNgEHCX6l55gBUmICMxgkpjaMpsZomMZo8Tkl2YgtrCA u8T+HU/AFrAIqEqsXL2aCWKZtcTl7rVMEBfJS+xqu8gKYnMK2Eh87O8Fs4WAajqeQszkF9CS WNN0nWUCo+AsJLfOQrh1FpJbFzAyr2IUSS0tzk3PLTbSK07MLS7NS9dLzs/dxAiMj23Hfm7Z wdj1LvgQowAHoxIPb8EjsSgh1sSy4srcQ4wSHMxKIrwsj4FCvCmJlVWpRfnxRaU5qcWHGKU5 WJTEeXv3rI4UEkhPLEnNTk0tSC2CyTJxcEo1MGrV1bT37ZOX0e72ZRd0eLhSpcCQWz7o8JLS 4KVClXtye9tmZU95tvLgLN5LJqppKirmN5mj9rLszbglELI0Nzx5oXWSkdiT9dmZAn9jf/VN NftUtfb4p98fOEzsE8vCHl54dNdHK9fhhY/NBtHw2NDopW6bt8l7nr81ZZnMy/uyfVn7XQ2+ KrEUZyQaajEXFScCANAjnOGLAgAA X-CMS-MailID: 20171123151007eucas1p1cb231b31169771df3f9d57e515057413 X-Msg-Generator: CA CMS-TYPE: 201P X-CMS-RootMailID: 20171123151007eucas1p1cb231b31169771df3f9d57e515057413 X-RootMTR: 20171123151007eucas1p1cb231b31169771df3f9d57e515057413 References: <20171123150914.31462-1-l.stelmach@samsung.com> Sender: linux-samsung-soc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-samsung-soc@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add support for True Random Number Generator found in Samsung Exynos 5250+ SoCs. Signed-off-by: Łukasz Stelmach --- MAINTAINERS | 7 + drivers/char/hw_random/Kconfig | 12 ++ drivers/char/hw_random/Makefile | 1 + drivers/char/hw_random/exynos-trng.c | 256 +++++++++++++++++++++++++++++++++++ 4 files changed, 276 insertions(+) create mode 100644 drivers/char/hw_random/exynos-trng.c diff --git a/MAINTAINERS b/MAINTAINERS index 2811a211632c..992074cca612 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11780,6 +11780,13 @@ S: Maintained F: drivers/crypto/exynos-rng.c F: Documentation/devicetree/bindings/rng/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 95a031e9eced..a788ac07081b 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -449,6 +449,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 f3728d008fff..5595df97da7a 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile @@ -14,6 +14,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..340e106cae24 --- /dev/null +++ b/drivers/char/hw_random/exynos-trng.c @@ -0,0 +1,256 @@ +/* + * 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_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; +}; + +struct exynos_trng_dev *exynos_trng_dev; + +static inline void exynos_trng_set_reg(struct exynos_trng_dev *trng, u16 reg, + u32 val) +{ + /* Check range of reg? */ + __raw_writel(val, trng->mem + reg); +} + +static inline u32 exynos_trng_get_reg(struct exynos_trng_dev *trng, u16 reg) +{ + /* Check range of reg? */ + return __raw_readl(trng->mem + reg); +} + +static int exynos_trng_do_read(struct hwrng *rng, void *data, size_t max, + bool wait) +{ + struct exynos_trng_dev *trng; + u32 val; + + max = max > (EXYNOS_TRNG_FIFO_LEN * 4) ? + (EXYNOS_TRNG_FIFO_LEN * 4) : max; + + trng = (struct exynos_trng_dev *)rng->priv; + + exynos_trng_set_reg(trng, EXYNOS_TRNG_FIFO_CTRL, max * 8); + 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; + unsigned long sss_rate; + u32 val; + + trng = (struct exynos_trng_dev *)rng->priv; + 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; + exynos_trng_set_reg(trng, EXYNOS_TRNG_CLKDIV, val); + + /* Enable the generator. */ + val = 1 << 31; + exynos_trng_set_reg(trng, EXYNOS_TRNG_CTRL, val); + + /* Disable post processing. /dev/hwrng is supposed to deliver + * unprocessed data. + */ + exynos_trng_set_reg(trng, EXYNOS_TRNG_POST_CTRL, 0); + + return 0; +} + +static int exynos_trng_probe(struct platform_device *pdev) +{ + struct exynos_trng_dev *trng; + struct resource *res; + int ret = -ENOMEM; + + if (exynos_trng_dev) + return -EEXIST; + + trng = devm_kzalloc(&pdev->dev, sizeof(*trng), GFP_KERNEL); + if (!trng) + goto err_ioremap; + + trng->rng.name = devm_kstrdup(&pdev->dev, dev_name(&pdev->dev), + GFP_KERNEL); + if (!trng->rng.name) + goto err_ioremap; + + 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, "Couldn't map IO resources.\n"); + ret = PTR_ERR(trng->mem); + goto err_ioremap; + } + + pm_runtime_enable(&pdev->dev); + ret = pm_runtime_get_sync(&pdev->dev); + if (ret < 0) { + dev_err(&pdev->dev, "pm_runtime_get_sync() failed: %d.\n", ret); + goto err_ioremap; + } + + trng->clk = devm_clk_get(&pdev->dev, "secss"); + if (IS_ERR(trng->clk)) { + /* XXX: EPROBE_DEFER ? */ + dev_err(&pdev->dev, "Couldn't get clock.\n"); + ret = PTR_ERR(trng->clk); + goto err_clock; + } + + ret = clk_prepare_enable(trng->clk); + if (ret) { + dev_err(&pdev->dev, "Unable to enable the clk: %d.\n", ret); + goto err_clock; + } + + ret = hwrng_register(&trng->rng); + if (ret) { + dev_err(&pdev->dev, "Couldn't 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: + trng->mem = NULL; + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + +err_ioremap: + dev_err(&pdev->dev, "Initialisation failed.\n"); + return ret; +} + +static int exynos_trng_remove(struct platform_device *pdev) +{ + exynos_trng_dev = NULL; + + 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, "pm_runtime_get_sync() failed: %d.\n", ret); + 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_rng_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");