1*7701d1ffSSean Wang /* 2*7701d1ffSSean Wang * Driver for Mediatek Hardware Random Number Generator 3*7701d1ffSSean Wang * 4*7701d1ffSSean Wang * Copyright (C) 2017 Sean Wang <sean.wang@mediatek.com> 5*7701d1ffSSean Wang * 6*7701d1ffSSean Wang * This program is free software; you can redistribute it and/or 7*7701d1ffSSean Wang * modify it under the terms of the GNU General Public License as 8*7701d1ffSSean Wang * published by the Free Software Foundation; either version 2 of 9*7701d1ffSSean Wang * the License, or (at your option) any later version. 10*7701d1ffSSean Wang * 11*7701d1ffSSean Wang * This program is distributed in the hope that it will be useful, 12*7701d1ffSSean Wang * but WITHOUT ANY WARRANTY; without even the implied warranty of 13*7701d1ffSSean Wang * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14*7701d1ffSSean Wang * GNU General Public License for more details. 15*7701d1ffSSean Wang */ 16*7701d1ffSSean Wang #define MTK_RNG_DEV KBUILD_MODNAME 17*7701d1ffSSean Wang 18*7701d1ffSSean Wang #include <linux/clk.h> 19*7701d1ffSSean Wang #include <linux/delay.h> 20*7701d1ffSSean Wang #include <linux/err.h> 21*7701d1ffSSean Wang #include <linux/hw_random.h> 22*7701d1ffSSean Wang #include <linux/io.h> 23*7701d1ffSSean Wang #include <linux/iopoll.h> 24*7701d1ffSSean Wang #include <linux/kernel.h> 25*7701d1ffSSean Wang #include <linux/module.h> 26*7701d1ffSSean Wang #include <linux/of.h> 27*7701d1ffSSean Wang #include <linux/platform_device.h> 28*7701d1ffSSean Wang 29*7701d1ffSSean Wang #define USEC_POLL 2 30*7701d1ffSSean Wang #define TIMEOUT_POLL 20 31*7701d1ffSSean Wang 32*7701d1ffSSean Wang #define RNG_CTRL 0x00 33*7701d1ffSSean Wang #define RNG_EN BIT(0) 34*7701d1ffSSean Wang #define RNG_READY BIT(31) 35*7701d1ffSSean Wang 36*7701d1ffSSean Wang #define RNG_DATA 0x08 37*7701d1ffSSean Wang 38*7701d1ffSSean Wang #define to_mtk_rng(p) container_of(p, struct mtk_rng, rng) 39*7701d1ffSSean Wang 40*7701d1ffSSean Wang struct mtk_rng { 41*7701d1ffSSean Wang void __iomem *base; 42*7701d1ffSSean Wang struct clk *clk; 43*7701d1ffSSean Wang struct hwrng rng; 44*7701d1ffSSean Wang }; 45*7701d1ffSSean Wang 46*7701d1ffSSean Wang static int mtk_rng_init(struct hwrng *rng) 47*7701d1ffSSean Wang { 48*7701d1ffSSean Wang struct mtk_rng *priv = to_mtk_rng(rng); 49*7701d1ffSSean Wang u32 val; 50*7701d1ffSSean Wang int err; 51*7701d1ffSSean Wang 52*7701d1ffSSean Wang err = clk_prepare_enable(priv->clk); 53*7701d1ffSSean Wang if (err) 54*7701d1ffSSean Wang return err; 55*7701d1ffSSean Wang 56*7701d1ffSSean Wang val = readl(priv->base + RNG_CTRL); 57*7701d1ffSSean Wang val |= RNG_EN; 58*7701d1ffSSean Wang writel(val, priv->base + RNG_CTRL); 59*7701d1ffSSean Wang 60*7701d1ffSSean Wang return 0; 61*7701d1ffSSean Wang } 62*7701d1ffSSean Wang 63*7701d1ffSSean Wang static void mtk_rng_cleanup(struct hwrng *rng) 64*7701d1ffSSean Wang { 65*7701d1ffSSean Wang struct mtk_rng *priv = to_mtk_rng(rng); 66*7701d1ffSSean Wang u32 val; 67*7701d1ffSSean Wang 68*7701d1ffSSean Wang val = readl(priv->base + RNG_CTRL); 69*7701d1ffSSean Wang val &= ~RNG_EN; 70*7701d1ffSSean Wang writel(val, priv->base + RNG_CTRL); 71*7701d1ffSSean Wang 72*7701d1ffSSean Wang clk_disable_unprepare(priv->clk); 73*7701d1ffSSean Wang } 74*7701d1ffSSean Wang 75*7701d1ffSSean Wang static bool mtk_rng_wait_ready(struct hwrng *rng, bool wait) 76*7701d1ffSSean Wang { 77*7701d1ffSSean Wang struct mtk_rng *priv = to_mtk_rng(rng); 78*7701d1ffSSean Wang int ready; 79*7701d1ffSSean Wang 80*7701d1ffSSean Wang ready = readl(priv->base + RNG_CTRL) & RNG_READY; 81*7701d1ffSSean Wang if (!ready && wait) 82*7701d1ffSSean Wang readl_poll_timeout_atomic(priv->base + RNG_CTRL, ready, 83*7701d1ffSSean Wang ready & RNG_READY, USEC_POLL, 84*7701d1ffSSean Wang TIMEOUT_POLL); 85*7701d1ffSSean Wang return !!ready; 86*7701d1ffSSean Wang } 87*7701d1ffSSean Wang 88*7701d1ffSSean Wang static int mtk_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait) 89*7701d1ffSSean Wang { 90*7701d1ffSSean Wang struct mtk_rng *priv = to_mtk_rng(rng); 91*7701d1ffSSean Wang int retval = 0; 92*7701d1ffSSean Wang 93*7701d1ffSSean Wang while (max >= sizeof(u32)) { 94*7701d1ffSSean Wang if (!mtk_rng_wait_ready(rng, wait)) 95*7701d1ffSSean Wang break; 96*7701d1ffSSean Wang 97*7701d1ffSSean Wang *(u32 *)buf = readl(priv->base + RNG_DATA); 98*7701d1ffSSean Wang retval += sizeof(u32); 99*7701d1ffSSean Wang buf += sizeof(u32); 100*7701d1ffSSean Wang max -= sizeof(u32); 101*7701d1ffSSean Wang } 102*7701d1ffSSean Wang 103*7701d1ffSSean Wang return retval || !wait ? retval : -EIO; 104*7701d1ffSSean Wang } 105*7701d1ffSSean Wang 106*7701d1ffSSean Wang static int mtk_rng_probe(struct platform_device *pdev) 107*7701d1ffSSean Wang { 108*7701d1ffSSean Wang struct resource *res; 109*7701d1ffSSean Wang int ret; 110*7701d1ffSSean Wang struct mtk_rng *priv; 111*7701d1ffSSean Wang 112*7701d1ffSSean Wang res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 113*7701d1ffSSean Wang if (!res) { 114*7701d1ffSSean Wang dev_err(&pdev->dev, "no iomem resource\n"); 115*7701d1ffSSean Wang return -ENXIO; 116*7701d1ffSSean Wang } 117*7701d1ffSSean Wang 118*7701d1ffSSean Wang priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 119*7701d1ffSSean Wang if (!priv) 120*7701d1ffSSean Wang return -ENOMEM; 121*7701d1ffSSean Wang 122*7701d1ffSSean Wang priv->rng.name = pdev->name; 123*7701d1ffSSean Wang priv->rng.init = mtk_rng_init; 124*7701d1ffSSean Wang priv->rng.cleanup = mtk_rng_cleanup; 125*7701d1ffSSean Wang priv->rng.read = mtk_rng_read; 126*7701d1ffSSean Wang 127*7701d1ffSSean Wang priv->clk = devm_clk_get(&pdev->dev, "rng"); 128*7701d1ffSSean Wang if (IS_ERR(priv->clk)) { 129*7701d1ffSSean Wang ret = PTR_ERR(priv->clk); 130*7701d1ffSSean Wang dev_err(&pdev->dev, "no clock for device: %d\n", ret); 131*7701d1ffSSean Wang return ret; 132*7701d1ffSSean Wang } 133*7701d1ffSSean Wang 134*7701d1ffSSean Wang priv->base = devm_ioremap_resource(&pdev->dev, res); 135*7701d1ffSSean Wang if (IS_ERR(priv->base)) 136*7701d1ffSSean Wang return PTR_ERR(priv->base); 137*7701d1ffSSean Wang 138*7701d1ffSSean Wang ret = devm_hwrng_register(&pdev->dev, &priv->rng); 139*7701d1ffSSean Wang if (ret) { 140*7701d1ffSSean Wang dev_err(&pdev->dev, "failed to register rng device: %d\n", 141*7701d1ffSSean Wang ret); 142*7701d1ffSSean Wang return ret; 143*7701d1ffSSean Wang } 144*7701d1ffSSean Wang 145*7701d1ffSSean Wang dev_info(&pdev->dev, "registered RNG driver\n"); 146*7701d1ffSSean Wang 147*7701d1ffSSean Wang return 0; 148*7701d1ffSSean Wang } 149*7701d1ffSSean Wang 150*7701d1ffSSean Wang static const struct of_device_id mtk_rng_match[] = { 151*7701d1ffSSean Wang { .compatible = "mediatek,mt7623-rng" }, 152*7701d1ffSSean Wang {}, 153*7701d1ffSSean Wang }; 154*7701d1ffSSean Wang MODULE_DEVICE_TABLE(of, mtk_rng_match); 155*7701d1ffSSean Wang 156*7701d1ffSSean Wang static struct platform_driver mtk_rng_driver = { 157*7701d1ffSSean Wang .probe = mtk_rng_probe, 158*7701d1ffSSean Wang .driver = { 159*7701d1ffSSean Wang .name = MTK_RNG_DEV, 160*7701d1ffSSean Wang .of_match_table = mtk_rng_match, 161*7701d1ffSSean Wang }, 162*7701d1ffSSean Wang }; 163*7701d1ffSSean Wang 164*7701d1ffSSean Wang module_platform_driver(mtk_rng_driver); 165*7701d1ffSSean Wang 166*7701d1ffSSean Wang MODULE_DESCRIPTION("Mediatek Random Number Generator Driver"); 167*7701d1ffSSean Wang MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>"); 168*7701d1ffSSean Wang MODULE_LICENSE("GPL"); 169