1*eb428ee0SVitaly Andrianov /* 2*eb428ee0SVitaly Andrianov * Random Number Generator driver for the Keystone SOC 3*eb428ee0SVitaly Andrianov * 4*eb428ee0SVitaly Andrianov * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com 5*eb428ee0SVitaly Andrianov * 6*eb428ee0SVitaly Andrianov * Authors: Sandeep Nair 7*eb428ee0SVitaly Andrianov * Vitaly Andrianov 8*eb428ee0SVitaly Andrianov * 9*eb428ee0SVitaly Andrianov * This program is free software; you can redistribute it and/or 10*eb428ee0SVitaly Andrianov * modify it under the terms of the GNU General Public License 11*eb428ee0SVitaly Andrianov * version 2 as published by the Free Software Foundation. 12*eb428ee0SVitaly Andrianov * 13*eb428ee0SVitaly Andrianov * This program is distributed in the hope that it will be useful, but 14*eb428ee0SVitaly Andrianov * WITHOUT ANY WARRANTY; without even the implied warranty of 15*eb428ee0SVitaly Andrianov * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16*eb428ee0SVitaly Andrianov * General Public License for more details. 17*eb428ee0SVitaly Andrianov */ 18*eb428ee0SVitaly Andrianov 19*eb428ee0SVitaly Andrianov #include <linux/hw_random.h> 20*eb428ee0SVitaly Andrianov #include <linux/kernel.h> 21*eb428ee0SVitaly Andrianov #include <linux/module.h> 22*eb428ee0SVitaly Andrianov #include <linux/io.h> 23*eb428ee0SVitaly Andrianov #include <linux/platform_device.h> 24*eb428ee0SVitaly Andrianov #include <linux/clk.h> 25*eb428ee0SVitaly Andrianov #include <linux/pm_runtime.h> 26*eb428ee0SVitaly Andrianov #include <linux/err.h> 27*eb428ee0SVitaly Andrianov #include <linux/regmap.h> 28*eb428ee0SVitaly Andrianov #include <linux/mfd/syscon.h> 29*eb428ee0SVitaly Andrianov #include <linux/of.h> 30*eb428ee0SVitaly Andrianov #include <linux/of_address.h> 31*eb428ee0SVitaly Andrianov #include <linux/delay.h> 32*eb428ee0SVitaly Andrianov 33*eb428ee0SVitaly Andrianov #define SA_CMD_STATUS_OFS 0x8 34*eb428ee0SVitaly Andrianov 35*eb428ee0SVitaly Andrianov /* TRNG enable control in SA System module*/ 36*eb428ee0SVitaly Andrianov #define SA_CMD_STATUS_REG_TRNG_ENABLE BIT(3) 37*eb428ee0SVitaly Andrianov 38*eb428ee0SVitaly Andrianov /* TRNG start control in TRNG module */ 39*eb428ee0SVitaly Andrianov #define TRNG_CNTL_REG_TRNG_ENABLE BIT(10) 40*eb428ee0SVitaly Andrianov 41*eb428ee0SVitaly Andrianov /* Data ready indicator in STATUS register */ 42*eb428ee0SVitaly Andrianov #define TRNG_STATUS_REG_READY BIT(0) 43*eb428ee0SVitaly Andrianov 44*eb428ee0SVitaly Andrianov /* Data ready clear control in INTACK register */ 45*eb428ee0SVitaly Andrianov #define TRNG_INTACK_REG_READY BIT(0) 46*eb428ee0SVitaly Andrianov 47*eb428ee0SVitaly Andrianov /* 48*eb428ee0SVitaly Andrianov * Number of samples taken to gather entropy during startup. 49*eb428ee0SVitaly Andrianov * If value is 0, the number of samples is 2^24 else 50*eb428ee0SVitaly Andrianov * equals value times 2^8. 51*eb428ee0SVitaly Andrianov */ 52*eb428ee0SVitaly Andrianov #define TRNG_DEF_STARTUP_CYCLES 0 53*eb428ee0SVitaly Andrianov #define TRNG_CNTL_REG_STARTUP_CYCLES_SHIFT 16 54*eb428ee0SVitaly Andrianov 55*eb428ee0SVitaly Andrianov /* 56*eb428ee0SVitaly Andrianov * Minimum number of samples taken to regenerate entropy 57*eb428ee0SVitaly Andrianov * If value is 0, the number of samples is 2^24 else 58*eb428ee0SVitaly Andrianov * equals value times 2^6. 59*eb428ee0SVitaly Andrianov */ 60*eb428ee0SVitaly Andrianov #define TRNG_DEF_MIN_REFILL_CYCLES 1 61*eb428ee0SVitaly Andrianov #define TRNG_CFG_REG_MIN_REFILL_CYCLES_SHIFT 0 62*eb428ee0SVitaly Andrianov 63*eb428ee0SVitaly Andrianov /* 64*eb428ee0SVitaly Andrianov * Maximum number of samples taken to regenerate entropy 65*eb428ee0SVitaly Andrianov * If value is 0, the number of samples is 2^24 else 66*eb428ee0SVitaly Andrianov * equals value times 2^8. 67*eb428ee0SVitaly Andrianov */ 68*eb428ee0SVitaly Andrianov #define TRNG_DEF_MAX_REFILL_CYCLES 0 69*eb428ee0SVitaly Andrianov #define TRNG_CFG_REG_MAX_REFILL_CYCLES_SHIFT 16 70*eb428ee0SVitaly Andrianov 71*eb428ee0SVitaly Andrianov /* Number of CLK input cycles between samples */ 72*eb428ee0SVitaly Andrianov #define TRNG_DEF_CLK_DIV_CYCLES 0 73*eb428ee0SVitaly Andrianov #define TRNG_CFG_REG_SAMPLE_DIV_SHIFT 8 74*eb428ee0SVitaly Andrianov 75*eb428ee0SVitaly Andrianov /* Maximum retries to get rng data */ 76*eb428ee0SVitaly Andrianov #define SA_MAX_RNG_DATA_RETRIES 5 77*eb428ee0SVitaly Andrianov /* Delay between retries (in usecs) */ 78*eb428ee0SVitaly Andrianov #define SA_RNG_DATA_RETRY_DELAY 5 79*eb428ee0SVitaly Andrianov 80*eb428ee0SVitaly Andrianov struct trng_regs { 81*eb428ee0SVitaly Andrianov u32 output_l; 82*eb428ee0SVitaly Andrianov u32 output_h; 83*eb428ee0SVitaly Andrianov u32 status; 84*eb428ee0SVitaly Andrianov u32 intmask; 85*eb428ee0SVitaly Andrianov u32 intack; 86*eb428ee0SVitaly Andrianov u32 control; 87*eb428ee0SVitaly Andrianov u32 config; 88*eb428ee0SVitaly Andrianov }; 89*eb428ee0SVitaly Andrianov 90*eb428ee0SVitaly Andrianov struct ks_sa_rng { 91*eb428ee0SVitaly Andrianov struct device *dev; 92*eb428ee0SVitaly Andrianov struct hwrng rng; 93*eb428ee0SVitaly Andrianov struct clk *clk; 94*eb428ee0SVitaly Andrianov struct regmap *regmap_cfg; 95*eb428ee0SVitaly Andrianov struct trng_regs *reg_rng; 96*eb428ee0SVitaly Andrianov }; 97*eb428ee0SVitaly Andrianov 98*eb428ee0SVitaly Andrianov static int ks_sa_rng_init(struct hwrng *rng) 99*eb428ee0SVitaly Andrianov { 100*eb428ee0SVitaly Andrianov u32 value; 101*eb428ee0SVitaly Andrianov struct device *dev = (struct device *)rng->priv; 102*eb428ee0SVitaly Andrianov struct ks_sa_rng *ks_sa_rng = dev_get_drvdata(dev); 103*eb428ee0SVitaly Andrianov 104*eb428ee0SVitaly Andrianov /* Enable RNG module */ 105*eb428ee0SVitaly Andrianov regmap_write_bits(ks_sa_rng->regmap_cfg, SA_CMD_STATUS_OFS, 106*eb428ee0SVitaly Andrianov SA_CMD_STATUS_REG_TRNG_ENABLE, 107*eb428ee0SVitaly Andrianov SA_CMD_STATUS_REG_TRNG_ENABLE); 108*eb428ee0SVitaly Andrianov 109*eb428ee0SVitaly Andrianov /* Configure RNG module */ 110*eb428ee0SVitaly Andrianov writel(0, &ks_sa_rng->reg_rng->control); 111*eb428ee0SVitaly Andrianov value = TRNG_DEF_STARTUP_CYCLES << TRNG_CNTL_REG_STARTUP_CYCLES_SHIFT; 112*eb428ee0SVitaly Andrianov writel(value, &ks_sa_rng->reg_rng->control); 113*eb428ee0SVitaly Andrianov 114*eb428ee0SVitaly Andrianov value = (TRNG_DEF_MIN_REFILL_CYCLES << 115*eb428ee0SVitaly Andrianov TRNG_CFG_REG_MIN_REFILL_CYCLES_SHIFT) | 116*eb428ee0SVitaly Andrianov (TRNG_DEF_MAX_REFILL_CYCLES << 117*eb428ee0SVitaly Andrianov TRNG_CFG_REG_MAX_REFILL_CYCLES_SHIFT) | 118*eb428ee0SVitaly Andrianov (TRNG_DEF_CLK_DIV_CYCLES << 119*eb428ee0SVitaly Andrianov TRNG_CFG_REG_SAMPLE_DIV_SHIFT); 120*eb428ee0SVitaly Andrianov 121*eb428ee0SVitaly Andrianov writel(value, &ks_sa_rng->reg_rng->config); 122*eb428ee0SVitaly Andrianov 123*eb428ee0SVitaly Andrianov /* Disable all interrupts from TRNG */ 124*eb428ee0SVitaly Andrianov writel(0, &ks_sa_rng->reg_rng->intmask); 125*eb428ee0SVitaly Andrianov 126*eb428ee0SVitaly Andrianov /* Enable RNG */ 127*eb428ee0SVitaly Andrianov value = readl(&ks_sa_rng->reg_rng->control); 128*eb428ee0SVitaly Andrianov value |= TRNG_CNTL_REG_TRNG_ENABLE; 129*eb428ee0SVitaly Andrianov writel(value, &ks_sa_rng->reg_rng->control); 130*eb428ee0SVitaly Andrianov 131*eb428ee0SVitaly Andrianov return 0; 132*eb428ee0SVitaly Andrianov } 133*eb428ee0SVitaly Andrianov 134*eb428ee0SVitaly Andrianov static void ks_sa_rng_cleanup(struct hwrng *rng) 135*eb428ee0SVitaly Andrianov { 136*eb428ee0SVitaly Andrianov struct device *dev = (struct device *)rng->priv; 137*eb428ee0SVitaly Andrianov struct ks_sa_rng *ks_sa_rng = dev_get_drvdata(dev); 138*eb428ee0SVitaly Andrianov 139*eb428ee0SVitaly Andrianov /* Disable RNG */ 140*eb428ee0SVitaly Andrianov writel(0, &ks_sa_rng->reg_rng->control); 141*eb428ee0SVitaly Andrianov regmap_write_bits(ks_sa_rng->regmap_cfg, SA_CMD_STATUS_OFS, 142*eb428ee0SVitaly Andrianov SA_CMD_STATUS_REG_TRNG_ENABLE, 0); 143*eb428ee0SVitaly Andrianov } 144*eb428ee0SVitaly Andrianov 145*eb428ee0SVitaly Andrianov static int ks_sa_rng_data_read(struct hwrng *rng, u32 *data) 146*eb428ee0SVitaly Andrianov { 147*eb428ee0SVitaly Andrianov struct device *dev = (struct device *)rng->priv; 148*eb428ee0SVitaly Andrianov struct ks_sa_rng *ks_sa_rng = dev_get_drvdata(dev); 149*eb428ee0SVitaly Andrianov 150*eb428ee0SVitaly Andrianov /* Read random data */ 151*eb428ee0SVitaly Andrianov data[0] = readl(&ks_sa_rng->reg_rng->output_l); 152*eb428ee0SVitaly Andrianov data[1] = readl(&ks_sa_rng->reg_rng->output_h); 153*eb428ee0SVitaly Andrianov 154*eb428ee0SVitaly Andrianov writel(TRNG_INTACK_REG_READY, &ks_sa_rng->reg_rng->intack); 155*eb428ee0SVitaly Andrianov 156*eb428ee0SVitaly Andrianov return sizeof(u32) * 2; 157*eb428ee0SVitaly Andrianov } 158*eb428ee0SVitaly Andrianov 159*eb428ee0SVitaly Andrianov static int ks_sa_rng_data_present(struct hwrng *rng, int wait) 160*eb428ee0SVitaly Andrianov { 161*eb428ee0SVitaly Andrianov struct device *dev = (struct device *)rng->priv; 162*eb428ee0SVitaly Andrianov struct ks_sa_rng *ks_sa_rng = dev_get_drvdata(dev); 163*eb428ee0SVitaly Andrianov 164*eb428ee0SVitaly Andrianov u32 ready; 165*eb428ee0SVitaly Andrianov int j; 166*eb428ee0SVitaly Andrianov 167*eb428ee0SVitaly Andrianov for (j = 0; j < SA_MAX_RNG_DATA_RETRIES; j++) { 168*eb428ee0SVitaly Andrianov ready = readl(&ks_sa_rng->reg_rng->status); 169*eb428ee0SVitaly Andrianov ready &= TRNG_STATUS_REG_READY; 170*eb428ee0SVitaly Andrianov 171*eb428ee0SVitaly Andrianov if (ready || !wait) 172*eb428ee0SVitaly Andrianov break; 173*eb428ee0SVitaly Andrianov 174*eb428ee0SVitaly Andrianov udelay(SA_RNG_DATA_RETRY_DELAY); 175*eb428ee0SVitaly Andrianov } 176*eb428ee0SVitaly Andrianov 177*eb428ee0SVitaly Andrianov return ready; 178*eb428ee0SVitaly Andrianov } 179*eb428ee0SVitaly Andrianov 180*eb428ee0SVitaly Andrianov static int ks_sa_rng_probe(struct platform_device *pdev) 181*eb428ee0SVitaly Andrianov { 182*eb428ee0SVitaly Andrianov struct ks_sa_rng *ks_sa_rng; 183*eb428ee0SVitaly Andrianov struct device *dev = &pdev->dev; 184*eb428ee0SVitaly Andrianov int ret; 185*eb428ee0SVitaly Andrianov struct resource *mem; 186*eb428ee0SVitaly Andrianov 187*eb428ee0SVitaly Andrianov ks_sa_rng = devm_kzalloc(dev, sizeof(*ks_sa_rng), GFP_KERNEL); 188*eb428ee0SVitaly Andrianov if (!ks_sa_rng) 189*eb428ee0SVitaly Andrianov return -ENOMEM; 190*eb428ee0SVitaly Andrianov 191*eb428ee0SVitaly Andrianov ks_sa_rng->dev = dev; 192*eb428ee0SVitaly Andrianov ks_sa_rng->rng = (struct hwrng) { 193*eb428ee0SVitaly Andrianov .name = "ks_sa_hwrng", 194*eb428ee0SVitaly Andrianov .init = ks_sa_rng_init, 195*eb428ee0SVitaly Andrianov .data_read = ks_sa_rng_data_read, 196*eb428ee0SVitaly Andrianov .data_present = ks_sa_rng_data_present, 197*eb428ee0SVitaly Andrianov .cleanup = ks_sa_rng_cleanup, 198*eb428ee0SVitaly Andrianov }; 199*eb428ee0SVitaly Andrianov ks_sa_rng->rng.priv = (unsigned long)dev; 200*eb428ee0SVitaly Andrianov 201*eb428ee0SVitaly Andrianov mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 202*eb428ee0SVitaly Andrianov ks_sa_rng->reg_rng = devm_ioremap_resource(dev, mem); 203*eb428ee0SVitaly Andrianov if (IS_ERR(ks_sa_rng->reg_rng)) 204*eb428ee0SVitaly Andrianov return PTR_ERR(ks_sa_rng->reg_rng); 205*eb428ee0SVitaly Andrianov 206*eb428ee0SVitaly Andrianov ks_sa_rng->regmap_cfg = 207*eb428ee0SVitaly Andrianov syscon_regmap_lookup_by_phandle(dev->of_node, 208*eb428ee0SVitaly Andrianov "ti,syscon-sa-cfg"); 209*eb428ee0SVitaly Andrianov 210*eb428ee0SVitaly Andrianov if (IS_ERR(ks_sa_rng->regmap_cfg)) { 211*eb428ee0SVitaly Andrianov dev_err(dev, "syscon_node_to_regmap failed\n"); 212*eb428ee0SVitaly Andrianov return -EINVAL; 213*eb428ee0SVitaly Andrianov } 214*eb428ee0SVitaly Andrianov 215*eb428ee0SVitaly Andrianov pm_runtime_enable(dev); 216*eb428ee0SVitaly Andrianov ret = pm_runtime_get_sync(dev); 217*eb428ee0SVitaly Andrianov if (ret < 0) { 218*eb428ee0SVitaly Andrianov dev_err(dev, "Failed to enable SA power-domain\n"); 219*eb428ee0SVitaly Andrianov pm_runtime_disable(dev); 220*eb428ee0SVitaly Andrianov return ret; 221*eb428ee0SVitaly Andrianov } 222*eb428ee0SVitaly Andrianov 223*eb428ee0SVitaly Andrianov platform_set_drvdata(pdev, ks_sa_rng); 224*eb428ee0SVitaly Andrianov 225*eb428ee0SVitaly Andrianov return devm_hwrng_register(&pdev->dev, &ks_sa_rng->rng); 226*eb428ee0SVitaly Andrianov } 227*eb428ee0SVitaly Andrianov 228*eb428ee0SVitaly Andrianov static int ks_sa_rng_remove(struct platform_device *pdev) 229*eb428ee0SVitaly Andrianov { 230*eb428ee0SVitaly Andrianov pm_runtime_put_sync(&pdev->dev); 231*eb428ee0SVitaly Andrianov pm_runtime_disable(&pdev->dev); 232*eb428ee0SVitaly Andrianov 233*eb428ee0SVitaly Andrianov return 0; 234*eb428ee0SVitaly Andrianov } 235*eb428ee0SVitaly Andrianov 236*eb428ee0SVitaly Andrianov static const struct of_device_id ks_sa_rng_dt_match[] = { 237*eb428ee0SVitaly Andrianov { 238*eb428ee0SVitaly Andrianov .compatible = "ti,keystone-rng", 239*eb428ee0SVitaly Andrianov }, 240*eb428ee0SVitaly Andrianov { }, 241*eb428ee0SVitaly Andrianov }; 242*eb428ee0SVitaly Andrianov MODULE_DEVICE_TABLE(of, ks_sa_rng_dt_match); 243*eb428ee0SVitaly Andrianov 244*eb428ee0SVitaly Andrianov static struct platform_driver ks_sa_rng_driver = { 245*eb428ee0SVitaly Andrianov .driver = { 246*eb428ee0SVitaly Andrianov .name = "ks-sa-rng", 247*eb428ee0SVitaly Andrianov .of_match_table = ks_sa_rng_dt_match, 248*eb428ee0SVitaly Andrianov }, 249*eb428ee0SVitaly Andrianov .probe = ks_sa_rng_probe, 250*eb428ee0SVitaly Andrianov .remove = ks_sa_rng_remove, 251*eb428ee0SVitaly Andrianov }; 252*eb428ee0SVitaly Andrianov 253*eb428ee0SVitaly Andrianov module_platform_driver(ks_sa_rng_driver); 254*eb428ee0SVitaly Andrianov 255*eb428ee0SVitaly Andrianov MODULE_DESCRIPTION("Keystone NETCP SA H/W Random Number Generator driver"); 256*eb428ee0SVitaly Andrianov MODULE_AUTHOR("Vitaly Andrianov <vitalya@ti.com>"); 257*eb428ee0SVitaly Andrianov MODULE_LICENSE("GPL"); 258