2019-06-01 11:08:59 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2016-02-09 00:17:53 +03:00
/*
* PIC32 RNG driver
*
* Joshua Henderson < joshua . henderson @ microchip . com >
* Copyright ( C ) 2016 Microchip Technology Inc . All rights reserved .
*/
# include <linux/clk.h>
# include <linux/clkdev.h>
# include <linux/err.h>
# include <linux/hw_random.h>
# include <linux/io.h>
# include <linux/kernel.h>
2023-07-28 16:48:27 +03:00
# include <linux/mod_devicetable.h>
2016-02-09 00:17:53 +03:00
# include <linux/module.h>
# include <linux/platform_device.h>
# include <linux/slab.h>
# define RNGCON 0x04
2023-07-04 20:32:02 +03:00
# define TRNGEN BIT(8)
# define TRNGMOD BIT(11)
2016-02-09 00:17:53 +03:00
# define RNGSEED1 0x18
# define RNGSEED2 0x1C
# define RNGRCNT 0x20
2023-07-04 20:32:02 +03:00
# define RCNT_MASK 0x7F
2016-02-09 00:17:53 +03:00
struct pic32_rng {
void __iomem * base ;
struct hwrng rng ;
} ;
/*
* The TRNG can generate up to 24 Mbps . This is a timeout that should be safe
* enough given the instructions in the loop and that the TRNG may not always
* be at maximum rate .
*/
# define RNG_TIMEOUT 500
2023-07-04 20:32:03 +03:00
static int pic32_rng_init ( struct hwrng * rng )
{
struct pic32_rng * priv = container_of ( rng , struct pic32_rng , rng ) ;
/* enable TRNG in enhanced mode */
writel ( TRNGEN | TRNGMOD , priv - > base + RNGCON ) ;
return 0 ;
}
2016-02-09 00:17:53 +03:00
static int pic32_rng_read ( struct hwrng * rng , void * buf , size_t max ,
bool wait )
{
struct pic32_rng * priv = container_of ( rng , struct pic32_rng , rng ) ;
u64 * data = buf ;
u32 t ;
unsigned int timeout = RNG_TIMEOUT ;
do {
t = readl ( priv - > base + RNGRCNT ) & RCNT_MASK ;
if ( t = = 64 ) {
/* TRNG value comes through the seed registers */
* data = ( ( u64 ) readl ( priv - > base + RNGSEED2 ) < < 32 ) +
readl ( priv - > base + RNGSEED1 ) ;
return 8 ;
}
} while ( wait & & - - timeout ) ;
return - EIO ;
}
2023-07-04 20:32:03 +03:00
static void pic32_rng_cleanup ( struct hwrng * rng )
{
struct pic32_rng * priv = container_of ( rng , struct pic32_rng , rng ) ;
writel ( 0 , priv - > base + RNGCON ) ;
}
2016-02-09 00:17:53 +03:00
static int pic32_rng_probe ( struct platform_device * pdev )
{
struct pic32_rng * priv ;
2023-07-04 20:32:01 +03:00
struct clk * clk ;
2016-02-09 00:17:53 +03:00
priv = devm_kzalloc ( & pdev - > dev , sizeof ( * priv ) , GFP_KERNEL ) ;
if ( ! priv )
return - ENOMEM ;
2019-10-16 13:46:18 +03:00
priv - > base = devm_platform_ioremap_resource ( pdev , 0 ) ;
2016-02-09 00:17:53 +03:00
if ( IS_ERR ( priv - > base ) )
return PTR_ERR ( priv - > base ) ;
2023-07-04 20:32:01 +03:00
clk = devm_clk_get_enabled ( & pdev - > dev , NULL ) ;
if ( IS_ERR ( clk ) )
return PTR_ERR ( clk ) ;
2016-02-09 00:17:53 +03:00
priv - > rng . name = pdev - > name ;
2023-07-04 20:32:03 +03:00
priv - > rng . init = pic32_rng_init ;
2016-02-09 00:17:53 +03:00
priv - > rng . read = pic32_rng_read ;
2023-07-04 20:32:03 +03:00
priv - > rng . cleanup = pic32_rng_cleanup ;
2016-02-09 00:17:53 +03:00
2023-07-04 20:32:03 +03:00
return devm_hwrng_register ( & pdev - > dev , & priv - > rng ) ;
2016-02-09 00:17:53 +03:00
}
2020-06-29 11:04:04 +03:00
static const struct of_device_id pic32_rng_of_match [ ] __maybe_unused = {
2016-02-09 00:17:53 +03:00
{ . compatible = " microchip,pic32mzda-rng " , } ,
{ /* sentinel */ }
} ;
MODULE_DEVICE_TABLE ( of , pic32_rng_of_match ) ;
static struct platform_driver pic32_rng_driver = {
. probe = pic32_rng_probe ,
. driver = {
. name = " pic32-rng " ,
2023-07-28 16:48:27 +03:00
. of_match_table = pic32_rng_of_match ,
2016-02-09 00:17:53 +03:00
} ,
} ;
module_platform_driver ( pic32_rng_driver ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Joshua Henderson <joshua.henderson@microchip.com> " ) ;
MODULE_DESCRIPTION ( " Microchip PIC32 RNG Driver " ) ;