Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2006-2007 PA Semi, Inc
0004  *
0005  * Maintained by: Olof Johansson <olof@lixom.net>
0006  *
0007  * Driver for the PWRficient onchip rng
0008  */
0009 
0010 #include <linux/module.h>
0011 #include <linux/kernel.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/hw_random.h>
0014 #include <linux/delay.h>
0015 #include <linux/of_address.h>
0016 #include <linux/of_platform.h>
0017 #include <linux/io.h>
0018 
0019 #define SDCRNG_CTL_REG          0x00
0020 #define   SDCRNG_CTL_FVLD_M     0x0000f000
0021 #define   SDCRNG_CTL_FVLD_S     12
0022 #define   SDCRNG_CTL_KSZ        0x00000800
0023 #define   SDCRNG_CTL_RSRC_CRG       0x00000010
0024 #define   SDCRNG_CTL_RSRC_RRG       0x00000000
0025 #define   SDCRNG_CTL_CE         0x00000004
0026 #define   SDCRNG_CTL_RE         0x00000002
0027 #define   SDCRNG_CTL_DR         0x00000001
0028 #define   SDCRNG_CTL_SELECT_RRG_RNG (SDCRNG_CTL_RE | SDCRNG_CTL_RSRC_RRG)
0029 #define   SDCRNG_CTL_SELECT_CRG_RNG (SDCRNG_CTL_CE | SDCRNG_CTL_RSRC_CRG)
0030 #define SDCRNG_VAL_REG          0x20
0031 
0032 #define MODULE_NAME "pasemi_rng"
0033 
0034 static int pasemi_rng_data_present(struct hwrng *rng, int wait)
0035 {
0036     void __iomem *rng_regs = (void __iomem *)rng->priv;
0037     int data, i;
0038 
0039     for (i = 0; i < 20; i++) {
0040         data = (in_le32(rng_regs + SDCRNG_CTL_REG)
0041             & SDCRNG_CTL_FVLD_M) ? 1 : 0;
0042         if (data || !wait)
0043             break;
0044         udelay(10);
0045     }
0046     return data;
0047 }
0048 
0049 static int pasemi_rng_data_read(struct hwrng *rng, u32 *data)
0050 {
0051     void __iomem *rng_regs = (void __iomem *)rng->priv;
0052     *data = in_le32(rng_regs + SDCRNG_VAL_REG);
0053     return 4;
0054 }
0055 
0056 static int pasemi_rng_init(struct hwrng *rng)
0057 {
0058     void __iomem *rng_regs = (void __iomem *)rng->priv;
0059     u32 ctl;
0060 
0061     ctl = SDCRNG_CTL_DR | SDCRNG_CTL_SELECT_RRG_RNG | SDCRNG_CTL_KSZ;
0062     out_le32(rng_regs + SDCRNG_CTL_REG, ctl);
0063     out_le32(rng_regs + SDCRNG_CTL_REG, ctl & ~SDCRNG_CTL_DR);
0064 
0065     return 0;
0066 }
0067 
0068 static void pasemi_rng_cleanup(struct hwrng *rng)
0069 {
0070     void __iomem *rng_regs = (void __iomem *)rng->priv;
0071     u32 ctl;
0072 
0073     ctl = SDCRNG_CTL_RE | SDCRNG_CTL_CE;
0074     out_le32(rng_regs + SDCRNG_CTL_REG,
0075          in_le32(rng_regs + SDCRNG_CTL_REG) & ~ctl);
0076 }
0077 
0078 static struct hwrng pasemi_rng = {
0079     .name       = MODULE_NAME,
0080     .init       = pasemi_rng_init,
0081     .cleanup    = pasemi_rng_cleanup,
0082     .data_present   = pasemi_rng_data_present,
0083     .data_read  = pasemi_rng_data_read,
0084 };
0085 
0086 static int rng_probe(struct platform_device *pdev)
0087 {
0088     void __iomem *rng_regs;
0089 
0090     rng_regs = devm_platform_ioremap_resource(pdev, 0);
0091     if (IS_ERR(rng_regs))
0092         return PTR_ERR(rng_regs);
0093 
0094     pasemi_rng.priv = (unsigned long)rng_regs;
0095 
0096     pr_info("Registering PA Semi RNG\n");
0097     return devm_hwrng_register(&pdev->dev, &pasemi_rng);
0098 }
0099 
0100 static const struct of_device_id rng_match[] = {
0101     { .compatible      = "1682m-rng", },
0102     { .compatible      = "pasemi,pwrficient-rng", },
0103     { },
0104 };
0105 MODULE_DEVICE_TABLE(of, rng_match);
0106 
0107 static struct platform_driver rng_driver = {
0108     .driver = {
0109         .name = "pasemi-rng",
0110         .of_match_table = rng_match,
0111     },
0112     .probe      = rng_probe,
0113 };
0114 
0115 module_platform_driver(rng_driver);
0116 
0117 MODULE_LICENSE("GPL");
0118 MODULE_AUTHOR("Egor Martovetsky <egor@pasemi.com>");
0119 MODULE_DESCRIPTION("H/W RNG driver for PA Semi processor");