brintos

brintos / linux-shallow public Read only

0
0
Text · 6.9 KiB · 36c3425 Raw
272 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Random Number Generator driver for the Keystone SOC4 *5 * Copyright (C) 2016 Texas Instruments Incorporated - https://www.ti.com6 *7 * Authors:	Sandeep Nair8 *		Vitaly Andrianov9 */10 11#include <linux/hw_random.h>12#include <linux/kernel.h>13#include <linux/module.h>14#include <linux/io.h>15#include <linux/platform_device.h>16#include <linux/clk.h>17#include <linux/pm_runtime.h>18#include <linux/err.h>19#include <linux/regmap.h>20#include <linux/mfd/syscon.h>21#include <linux/of.h>22#include <linux/of_address.h>23#include <linux/delay.h>24#include <linux/timekeeping.h>25 26#define SA_CMD_STATUS_OFS			0x827 28/* TRNG enable control in SA System module*/29#define SA_CMD_STATUS_REG_TRNG_ENABLE		BIT(3)30 31/* TRNG start control in TRNG module */32#define TRNG_CNTL_REG_TRNG_ENABLE		BIT(10)33 34/* Data ready indicator in STATUS register */35#define TRNG_STATUS_REG_READY			BIT(0)36 37/* Data ready clear control in INTACK register */38#define TRNG_INTACK_REG_READY			BIT(0)39 40/*41 * Number of samples taken to gather entropy during startup.42 * If value is 0, the number of samples is 2^24 else43 * equals value times 2^8.44 */45#define TRNG_DEF_STARTUP_CYCLES			046#define TRNG_CNTL_REG_STARTUP_CYCLES_SHIFT	1647 48/*49 * Minimum number of samples taken to regenerate entropy50 * If value is 0, the number of samples is 2^24 else51 * equals value times 2^6.52 */53#define TRNG_DEF_MIN_REFILL_CYCLES		154#define TRNG_CFG_REG_MIN_REFILL_CYCLES_SHIFT	055 56/*57 * Maximum number of samples taken to regenerate entropy58 * If value is 0, the number of samples is 2^24 else59 * equals value times 2^8.60 */61#define TRNG_DEF_MAX_REFILL_CYCLES		062#define TRNG_CFG_REG_MAX_REFILL_CYCLES_SHIFT	1663 64/* Number of CLK input cycles between samples */65#define TRNG_DEF_CLK_DIV_CYCLES			066#define TRNG_CFG_REG_SAMPLE_DIV_SHIFT		867 68/* Maximum retries to get rng data */69#define SA_MAX_RNG_DATA_RETRIES			570/* Delay between retries (in usecs) */71#define SA_RNG_DATA_RETRY_DELAY			572 73struct trng_regs {74	u32	output_l;75	u32	output_h;76	u32	status;77	u32	intmask;78	u32	intack;79	u32	control;80	u32	config;81};82 83struct ks_sa_rng {84	struct hwrng	rng;85	struct clk	*clk;86	struct regmap	*regmap_cfg;87	struct trng_regs __iomem *reg_rng;88	u64 ready_ts;89	unsigned int refill_delay_ns;90};91 92static unsigned int cycles_to_ns(unsigned long clk_rate, unsigned int cycles)93{94	return DIV_ROUND_UP_ULL((TRNG_DEF_CLK_DIV_CYCLES + 1) * 1000000000ull *95				cycles, clk_rate);96}97 98static unsigned int startup_delay_ns(unsigned long clk_rate)99{100	if (!TRNG_DEF_STARTUP_CYCLES)101		return cycles_to_ns(clk_rate, BIT(24));102	return cycles_to_ns(clk_rate, 256 * TRNG_DEF_STARTUP_CYCLES);103}104 105static unsigned int refill_delay_ns(unsigned long clk_rate)106{107	if (!TRNG_DEF_MAX_REFILL_CYCLES)108		return cycles_to_ns(clk_rate, BIT(24));109	return cycles_to_ns(clk_rate, 256 * TRNG_DEF_MAX_REFILL_CYCLES);110}111 112static int ks_sa_rng_init(struct hwrng *rng)113{114	u32 value;115	struct ks_sa_rng *ks_sa_rng = container_of(rng, struct ks_sa_rng, rng);116	unsigned long clk_rate = clk_get_rate(ks_sa_rng->clk);117 118	/* Enable RNG module */119	regmap_write_bits(ks_sa_rng->regmap_cfg, SA_CMD_STATUS_OFS,120			  SA_CMD_STATUS_REG_TRNG_ENABLE,121			  SA_CMD_STATUS_REG_TRNG_ENABLE);122 123	/* Configure RNG module */124	writel(0, &ks_sa_rng->reg_rng->control);125	value = TRNG_DEF_STARTUP_CYCLES << TRNG_CNTL_REG_STARTUP_CYCLES_SHIFT;126	writel(value, &ks_sa_rng->reg_rng->control);127 128	value =	(TRNG_DEF_MIN_REFILL_CYCLES <<129		 TRNG_CFG_REG_MIN_REFILL_CYCLES_SHIFT) |130		(TRNG_DEF_MAX_REFILL_CYCLES <<131		 TRNG_CFG_REG_MAX_REFILL_CYCLES_SHIFT) |132		(TRNG_DEF_CLK_DIV_CYCLES <<133		 TRNG_CFG_REG_SAMPLE_DIV_SHIFT);134 135	writel(value, &ks_sa_rng->reg_rng->config);136 137	/* Disable all interrupts from TRNG */138	writel(0, &ks_sa_rng->reg_rng->intmask);139 140	/* Enable RNG */141	value = readl(&ks_sa_rng->reg_rng->control);142	value |= TRNG_CNTL_REG_TRNG_ENABLE;143	writel(value, &ks_sa_rng->reg_rng->control);144 145	ks_sa_rng->refill_delay_ns = refill_delay_ns(clk_rate);146	ks_sa_rng->ready_ts = ktime_get_ns() +147			      startup_delay_ns(clk_rate);148 149	return 0;150}151 152static void ks_sa_rng_cleanup(struct hwrng *rng)153{154	struct ks_sa_rng *ks_sa_rng = container_of(rng, struct ks_sa_rng, rng);155 156	/* Disable RNG */157	writel(0, &ks_sa_rng->reg_rng->control);158	regmap_write_bits(ks_sa_rng->regmap_cfg, SA_CMD_STATUS_OFS,159			  SA_CMD_STATUS_REG_TRNG_ENABLE, 0);160}161 162static int ks_sa_rng_data_read(struct hwrng *rng, u32 *data)163{164	struct ks_sa_rng *ks_sa_rng = container_of(rng, struct ks_sa_rng, rng);165 166	/* Read random data */167	data[0] = readl(&ks_sa_rng->reg_rng->output_l);168	data[1] = readl(&ks_sa_rng->reg_rng->output_h);169 170	writel(TRNG_INTACK_REG_READY, &ks_sa_rng->reg_rng->intack);171	ks_sa_rng->ready_ts = ktime_get_ns() + ks_sa_rng->refill_delay_ns;172 173	return sizeof(u32) * 2;174}175 176static int ks_sa_rng_data_present(struct hwrng *rng, int wait)177{178	struct ks_sa_rng *ks_sa_rng = container_of(rng, struct ks_sa_rng, rng);179	u64 now = ktime_get_ns();180 181	u32	ready;182	int	j;183 184	if (wait && now < ks_sa_rng->ready_ts) {185		/* Max delay expected here is 81920000 ns */186		unsigned long min_delay =187			DIV_ROUND_UP((u32)(ks_sa_rng->ready_ts - now), 1000);188 189		usleep_range(min_delay, min_delay + SA_RNG_DATA_RETRY_DELAY);190	}191 192	for (j = 0; j < SA_MAX_RNG_DATA_RETRIES; j++) {193		ready = readl(&ks_sa_rng->reg_rng->status);194		ready &= TRNG_STATUS_REG_READY;195 196		if (ready || !wait)197			break;198 199		udelay(SA_RNG_DATA_RETRY_DELAY);200	}201 202	return ready;203}204 205static int ks_sa_rng_probe(struct platform_device *pdev)206{207	struct ks_sa_rng	*ks_sa_rng;208	struct device		*dev = &pdev->dev;209	int			ret;210 211	ks_sa_rng = devm_kzalloc(dev, sizeof(*ks_sa_rng), GFP_KERNEL);212	if (!ks_sa_rng)213		return -ENOMEM;214 215	ks_sa_rng->rng = (struct hwrng) {216		.name = "ks_sa_hwrng",217		.init = ks_sa_rng_init,218		.data_read = ks_sa_rng_data_read,219		.data_present = ks_sa_rng_data_present,220		.cleanup = ks_sa_rng_cleanup,221	};222 223	ks_sa_rng->reg_rng = devm_platform_ioremap_resource(pdev, 0);224	if (IS_ERR(ks_sa_rng->reg_rng))225		return PTR_ERR(ks_sa_rng->reg_rng);226 227	ks_sa_rng->regmap_cfg =228		syscon_regmap_lookup_by_phandle(dev->of_node,229						"ti,syscon-sa-cfg");230 231	if (IS_ERR(ks_sa_rng->regmap_cfg))232		return dev_err_probe(dev, -EINVAL, "syscon_node_to_regmap failed\n");233 234	pm_runtime_enable(dev);235	ret = pm_runtime_resume_and_get(dev);236	if (ret < 0) {237		pm_runtime_disable(dev);238		return dev_err_probe(dev, ret, "Failed to enable SA power-domain\n");239	}240 241	return devm_hwrng_register(&pdev->dev, &ks_sa_rng->rng);242}243 244static void ks_sa_rng_remove(struct platform_device *pdev)245{246	pm_runtime_put_sync(&pdev->dev);247	pm_runtime_disable(&pdev->dev);248}249 250static const struct of_device_id ks_sa_rng_dt_match[] = {251	{252		.compatible = "ti,keystone-rng",253	},254	{ },255};256MODULE_DEVICE_TABLE(of, ks_sa_rng_dt_match);257 258static struct platform_driver ks_sa_rng_driver = {259	.driver		= {260		.name	= "ks-sa-rng",261		.of_match_table = ks_sa_rng_dt_match,262	},263	.probe		= ks_sa_rng_probe,264	.remove_new	= ks_sa_rng_remove,265};266 267module_platform_driver(ks_sa_rng_driver);268 269MODULE_DESCRIPTION("Keystone NETCP SA H/W Random Number Generator driver");270MODULE_AUTHOR("Vitaly Andrianov <vitalya@ti.com>");271MODULE_LICENSE("GPL");272