LCOV - code coverage report
Current view: top level - drivers/char/hw_random - bcm2835-rng.c (source / functions) Hit Total Coverage
Test: Real Lines: 40 49 81.6 %
Date: 2020-10-17 15:46:16 Functions: 0 6 0.0 %
Legend: Neither, QEMU, Real, Both Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0
       2                 :            : /*
       3                 :            :  * Copyright (c) 2010-2012 Broadcom. All rights reserved.
       4                 :            :  * Copyright (c) 2013 Lubomir Rintel
       5                 :            :  */
       6                 :            : 
       7                 :            : #include <linux/hw_random.h>
       8                 :            : #include <linux/io.h>
       9                 :            : #include <linux/kernel.h>
      10                 :            : #include <linux/module.h>
      11                 :            : #include <linux/of_address.h>
      12                 :            : #include <linux/of_platform.h>
      13                 :            : #include <linux/platform_device.h>
      14                 :            : #include <linux/printk.h>
      15                 :            : #include <linux/clk.h>
      16                 :            : 
      17                 :            : #define RNG_CTRL        0x0
      18                 :            : #define RNG_STATUS      0x4
      19                 :            : #define RNG_DATA        0x8
      20                 :            : #define RNG_INT_MASK    0x10
      21                 :            : 
      22                 :            : /* enable rng */
      23                 :            : #define RNG_RBGEN       0x1
      24                 :            : 
      25                 :            : /* the initial numbers generated are "less random" so will be discarded */
      26                 :            : #define RNG_WARMUP_COUNT 0x40000
      27                 :            : 
      28                 :            : #define RNG_INT_OFF     0x1
      29                 :            : 
      30                 :            : struct bcm2835_rng_priv {
      31                 :            :         struct hwrng rng;
      32                 :            :         void __iomem *base;
      33                 :            :         bool mask_interrupts;
      34                 :            :         struct clk *clk;
      35                 :            : };
      36                 :            : 
      37                 :            : static inline struct bcm2835_rng_priv *to_rng_priv(struct hwrng *rng)
      38                 :            : {
      39                 :            :         return container_of(rng, struct bcm2835_rng_priv, rng);
      40                 :            : }
      41                 :            : 
      42                 :            : static inline u32 rng_readl(struct bcm2835_rng_priv *priv, u32 offset)
      43                 :            : {
      44                 :            :         /* MIPS chips strapped for BE will automagically configure the
      45                 :            :          * peripheral registers for CPU-native byte order.
      46                 :            :          */
      47                 :            :         if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
      48                 :            :                 return __raw_readl(priv->base + offset);
      49                 :            :         else
      50                 :          3 :                 return readl(priv->base + offset);
      51                 :            : }
      52                 :            : 
      53                 :            : static inline void rng_writel(struct bcm2835_rng_priv *priv, u32 val,
      54                 :            :                               u32 offset)
      55                 :            : {
      56                 :            :         if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
      57                 :            :                 __raw_writel(val, priv->base + offset);
      58                 :            :         else
      59                 :          3 :                 writel(val, priv->base + offset);
      60                 :            : }
      61                 :            : 
      62                 :          3 : static int bcm2835_rng_read(struct hwrng *rng, void *buf, size_t max,
      63                 :            :                                bool wait)
      64                 :            : {
      65                 :            :         struct bcm2835_rng_priv *priv = to_rng_priv(rng);
      66                 :          3 :         u32 max_words = max / sizeof(u32);
      67                 :            :         u32 num_words, count;
      68                 :            : 
      69                 :          3 :         while ((rng_readl(priv, RNG_STATUS) >> 24) == 0) {
      70                 :          2 :                 if (!wait)
      71                 :            :                         return 0;
      72                 :          2 :                 cpu_relax();
      73                 :            :         }
      74                 :            : 
      75                 :          3 :         num_words = rng_readl(priv, RNG_STATUS) >> 24;
      76                 :          3 :         if (num_words > max_words)
      77                 :            :                 num_words = max_words;
      78                 :            : 
      79                 :          3 :         for (count = 0; count < num_words; count++)
      80                 :          3 :                 ((u32 *)buf)[count] = rng_readl(priv, RNG_DATA);
      81                 :            : 
      82                 :          3 :         return num_words * sizeof(u32);
      83                 :            : }
      84                 :            : 
      85                 :          3 : static int bcm2835_rng_init(struct hwrng *rng)
      86                 :            : {
      87                 :            :         struct bcm2835_rng_priv *priv = to_rng_priv(rng);
      88                 :            :         int ret = 0;
      89                 :            :         u32 val;
      90                 :            : 
      91                 :          3 :         if (!IS_ERR(priv->clk)) {
      92                 :          0 :                 ret = clk_prepare_enable(priv->clk);
      93                 :          0 :                 if (ret)
      94                 :            :                         return ret;
      95                 :            :         }
      96                 :            : 
      97                 :          3 :         if (priv->mask_interrupts) {
      98                 :            :                 /* mask the interrupt */
      99                 :            :                 val = rng_readl(priv, RNG_INT_MASK);
     100                 :          0 :                 val |= RNG_INT_OFF;
     101                 :            :                 rng_writel(priv, val, RNG_INT_MASK);
     102                 :            :         }
     103                 :            : 
     104                 :            :         /* set warm-up count & enable */
     105                 :          3 :         if (!(rng_readl(priv, RNG_CTRL) & RNG_RBGEN)) {
     106                 :            :                 rng_writel(priv, RNG_WARMUP_COUNT, RNG_STATUS);
     107                 :            :                 rng_writel(priv, RNG_RBGEN, RNG_CTRL);
     108                 :            :         }
     109                 :            : 
     110                 :          3 :         return ret;
     111                 :            : }
     112                 :            : 
     113                 :          0 : static void bcm2835_rng_cleanup(struct hwrng *rng)
     114                 :            : {
     115                 :            :         struct bcm2835_rng_priv *priv = to_rng_priv(rng);
     116                 :            : 
     117                 :            :         /* disable rng hardware */
     118                 :            :         rng_writel(priv, 0, RNG_CTRL);
     119                 :            : 
     120                 :          0 :         if (!IS_ERR(priv->clk))
     121                 :            :                 clk_disable_unprepare(priv->clk);
     122                 :          0 : }
     123                 :            : 
     124                 :            : struct bcm2835_rng_of_data {
     125                 :            :         bool mask_interrupts;
     126                 :            : };
     127                 :            : 
     128                 :            : static const struct bcm2835_rng_of_data nsp_rng_of_data = {
     129                 :            :         .mask_interrupts = true,
     130                 :            : };
     131                 :            : 
     132                 :            : static const struct of_device_id bcm2835_rng_of_match[] = {
     133                 :            :         { .compatible = "brcm,bcm2835-rng"},
     134                 :            :         { .compatible = "brcm,bcm-nsp-rng", .data = &nsp_rng_of_data },
     135                 :            :         { .compatible = "brcm,bcm5301x-rng", .data = &nsp_rng_of_data },
     136                 :            :         { .compatible = "brcm,bcm6368-rng"},
     137                 :            :         {},
     138                 :            : };
     139                 :            : 
     140                 :          3 : static int bcm2835_rng_probe(struct platform_device *pdev)
     141                 :            : {
     142                 :            :         const struct bcm2835_rng_of_data *of_data;
     143                 :          3 :         struct device *dev = &pdev->dev;
     144                 :          3 :         struct device_node *np = dev->of_node;
     145                 :            :         const struct of_device_id *rng_id;
     146                 :            :         struct bcm2835_rng_priv *priv;
     147                 :            :         struct resource *r;
     148                 :            :         int err;
     149                 :            : 
     150                 :            :         priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
     151                 :          3 :         if (!priv)
     152                 :            :                 return -ENOMEM;
     153                 :            : 
     154                 :            :         platform_set_drvdata(pdev, priv);
     155                 :            : 
     156                 :          3 :         r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
     157                 :            : 
     158                 :            :         /* map peripheral */
     159                 :          3 :         priv->base = devm_ioremap_resource(dev, r);
     160                 :          3 :         if (IS_ERR(priv->base))
     161                 :          0 :                 return PTR_ERR(priv->base);
     162                 :            : 
     163                 :            :         /* Clock is optional on most platforms */
     164                 :          3 :         priv->clk = devm_clk_get(dev, NULL);
     165                 :          3 :         if (IS_ERR(priv->clk) && PTR_ERR(priv->clk) == -EPROBE_DEFER)
     166                 :            :                 return -EPROBE_DEFER;
     167                 :            : 
     168                 :          3 :         priv->rng.name = pdev->name;
     169                 :          3 :         priv->rng.init = bcm2835_rng_init;
     170                 :          3 :         priv->rng.read = bcm2835_rng_read;
     171                 :          3 :         priv->rng.cleanup = bcm2835_rng_cleanup;
     172                 :            : 
     173                 :          3 :         if (dev_of_node(dev)) {
     174                 :          3 :                 rng_id = of_match_node(bcm2835_rng_of_match, np);
     175                 :          3 :                 if (!rng_id)
     176                 :            :                         return -EINVAL;
     177                 :            : 
     178                 :            :                 /* Check for rng init function, execute it */
     179                 :          3 :                 of_data = rng_id->data;
     180                 :          3 :                 if (of_data)
     181                 :          0 :                         priv->mask_interrupts = of_data->mask_interrupts;
     182                 :            :         }
     183                 :            : 
     184                 :            :         /* register driver */
     185                 :          3 :         err = devm_hwrng_register(dev, &priv->rng);
     186                 :          3 :         if (err)
     187                 :          0 :                 dev_err(dev, "hwrng registration failed\n");
     188                 :            :         else
     189                 :          3 :                 dev_info(dev, "hwrng registered\n");
     190                 :            : 
     191                 :          3 :         return err;
     192                 :            : }
     193                 :            : 
     194                 :            : MODULE_DEVICE_TABLE(of, bcm2835_rng_of_match);
     195                 :            : 
     196                 :            : static struct platform_device_id bcm2835_rng_devtype[] = {
     197                 :            :         { .name = "bcm2835-rng" },
     198                 :            :         { .name = "bcm63xx-rng" },
     199                 :            :         { /* sentinel */ }
     200                 :            : };
     201                 :            : MODULE_DEVICE_TABLE(platform, bcm2835_rng_devtype);
     202                 :            : 
     203                 :            : static struct platform_driver bcm2835_rng_driver = {
     204                 :            :         .driver = {
     205                 :            :                 .name = "bcm2835-rng",
     206                 :            :                 .of_match_table = bcm2835_rng_of_match,
     207                 :            :         },
     208                 :            :         .probe          = bcm2835_rng_probe,
     209                 :            :         .id_table       = bcm2835_rng_devtype,
     210                 :            : };
     211                 :          3 : module_platform_driver(bcm2835_rng_driver);
     212                 :            : 
     213                 :            : MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>");
     214                 :            : MODULE_DESCRIPTION("BCM2835 Random Number Generator (RNG) driver");
     215                 :            : MODULE_LICENSE("GPL v2");
    

Generated by: LCOV version 1.14