pasemi-rng.c (2999B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (C) 2006-2007 PA Semi, Inc 4 * 5 * Maintained by: Olof Johansson <olof@lixom.net> 6 * 7 * Driver for the PWRficient onchip rng 8 */ 9 10#include <linux/module.h> 11#include <linux/kernel.h> 12#include <linux/platform_device.h> 13#include <linux/hw_random.h> 14#include <linux/delay.h> 15#include <linux/of_address.h> 16#include <linux/of_platform.h> 17#include <linux/io.h> 18 19#define SDCRNG_CTL_REG 0x00 20#define SDCRNG_CTL_FVLD_M 0x0000f000 21#define SDCRNG_CTL_FVLD_S 12 22#define SDCRNG_CTL_KSZ 0x00000800 23#define SDCRNG_CTL_RSRC_CRG 0x00000010 24#define SDCRNG_CTL_RSRC_RRG 0x00000000 25#define SDCRNG_CTL_CE 0x00000004 26#define SDCRNG_CTL_RE 0x00000002 27#define SDCRNG_CTL_DR 0x00000001 28#define SDCRNG_CTL_SELECT_RRG_RNG (SDCRNG_CTL_RE | SDCRNG_CTL_RSRC_RRG) 29#define SDCRNG_CTL_SELECT_CRG_RNG (SDCRNG_CTL_CE | SDCRNG_CTL_RSRC_CRG) 30#define SDCRNG_VAL_REG 0x20 31 32#define MODULE_NAME "pasemi_rng" 33 34static int pasemi_rng_data_present(struct hwrng *rng, int wait) 35{ 36 void __iomem *rng_regs = (void __iomem *)rng->priv; 37 int data, i; 38 39 for (i = 0; i < 20; i++) { 40 data = (in_le32(rng_regs + SDCRNG_CTL_REG) 41 & SDCRNG_CTL_FVLD_M) ? 1 : 0; 42 if (data || !wait) 43 break; 44 udelay(10); 45 } 46 return data; 47} 48 49static int pasemi_rng_data_read(struct hwrng *rng, u32 *data) 50{ 51 void __iomem *rng_regs = (void __iomem *)rng->priv; 52 *data = in_le32(rng_regs + SDCRNG_VAL_REG); 53 return 4; 54} 55 56static int pasemi_rng_init(struct hwrng *rng) 57{ 58 void __iomem *rng_regs = (void __iomem *)rng->priv; 59 u32 ctl; 60 61 ctl = SDCRNG_CTL_DR | SDCRNG_CTL_SELECT_RRG_RNG | SDCRNG_CTL_KSZ; 62 out_le32(rng_regs + SDCRNG_CTL_REG, ctl); 63 out_le32(rng_regs + SDCRNG_CTL_REG, ctl & ~SDCRNG_CTL_DR); 64 65 return 0; 66} 67 68static void pasemi_rng_cleanup(struct hwrng *rng) 69{ 70 void __iomem *rng_regs = (void __iomem *)rng->priv; 71 u32 ctl; 72 73 ctl = SDCRNG_CTL_RE | SDCRNG_CTL_CE; 74 out_le32(rng_regs + SDCRNG_CTL_REG, 75 in_le32(rng_regs + SDCRNG_CTL_REG) & ~ctl); 76} 77 78static struct hwrng pasemi_rng = { 79 .name = MODULE_NAME, 80 .init = pasemi_rng_init, 81 .cleanup = pasemi_rng_cleanup, 82 .data_present = pasemi_rng_data_present, 83 .data_read = pasemi_rng_data_read, 84}; 85 86static int rng_probe(struct platform_device *pdev) 87{ 88 void __iomem *rng_regs; 89 90 rng_regs = devm_platform_ioremap_resource(pdev, 0); 91 if (IS_ERR(rng_regs)) 92 return PTR_ERR(rng_regs); 93 94 pasemi_rng.priv = (unsigned long)rng_regs; 95 96 pr_info("Registering PA Semi RNG\n"); 97 return devm_hwrng_register(&pdev->dev, &pasemi_rng); 98} 99 100static const struct of_device_id rng_match[] = { 101 { .compatible = "1682m-rng", }, 102 { .compatible = "pasemi,pwrficient-rng", }, 103 { }, 104}; 105MODULE_DEVICE_TABLE(of, rng_match); 106 107static struct platform_driver rng_driver = { 108 .driver = { 109 .name = "pasemi-rng", 110 .of_match_table = rng_match, 111 }, 112 .probe = rng_probe, 113}; 114 115module_platform_driver(rng_driver); 116 117MODULE_LICENSE("GPL"); 118MODULE_AUTHOR("Egor Martovetsky <egor@pasemi.com>"); 119MODULE_DESCRIPTION("H/W RNG driver for PA Semi processor");