brintos

brintos / linux-shallow public Read only

0
0
Text · 14.1 KiB · 4914a87 Raw
569 lines · c
1/*2 * omap-rng.c - RNG driver for TI OMAP CPU family3 *4 * Author: Deepak Saxena <dsaxena@plexity.net>5 *6 * Copyright 2005 (c) MontaVista Software, Inc.7 *8 * Mostly based on original driver:9 *10 * Copyright (C) 2005 Nokia Corporation11 * Author: Juha Yrjölä <juha.yrjola@nokia.com>12 *13 * This file is licensed under  the terms of the GNU General Public14 * License version 2. This program is licensed "as is" without any15 * warranty of any kind, whether express or implied.16 */17 18#include <linux/module.h>19#include <linux/init.h>20#include <linux/random.h>21#include <linux/err.h>22#include <linux/platform_device.h>23#include <linux/hw_random.h>24#include <linux/delay.h>25#include <linux/kernel.h>26#include <linux/slab.h>27#include <linux/pm_runtime.h>28#include <linux/of.h>29#include <linux/interrupt.h>30#include <linux/clk.h>31#include <linux/io.h>32 33#define RNG_REG_STATUS_RDY			(1 << 0)34 35#define RNG_REG_INTACK_RDY_MASK			(1 << 0)36#define RNG_REG_INTACK_SHUTDOWN_OFLO_MASK	(1 << 1)37#define RNG_SHUTDOWN_OFLO_MASK			(1 << 1)38 39#define RNG_CONTROL_STARTUP_CYCLES_SHIFT	1640#define RNG_CONTROL_STARTUP_CYCLES_MASK		(0xffff << 16)41#define RNG_CONTROL_ENABLE_TRNG_SHIFT		1042#define RNG_CONTROL_ENABLE_TRNG_MASK		(1 << 10)43 44#define RNG_CONFIG_MAX_REFIL_CYCLES_SHIFT	1645#define RNG_CONFIG_MAX_REFIL_CYCLES_MASK	(0xffff << 16)46#define RNG_CONFIG_MIN_REFIL_CYCLES_SHIFT	047#define RNG_CONFIG_MIN_REFIL_CYCLES_MASK	(0xff << 0)48 49#define RNG_CONTROL_STARTUP_CYCLES		0xff50#define RNG_CONFIG_MIN_REFIL_CYCLES		0x2151#define RNG_CONFIG_MAX_REFIL_CYCLES		0x2252 53#define RNG_ALARMCNT_ALARM_TH_SHIFT		0x054#define RNG_ALARMCNT_ALARM_TH_MASK		(0xff << 0)55#define RNG_ALARMCNT_SHUTDOWN_TH_SHIFT		1656#define RNG_ALARMCNT_SHUTDOWN_TH_MASK		(0x1f << 16)57#define RNG_ALARM_THRESHOLD			0xff58#define RNG_SHUTDOWN_THRESHOLD			0x459 60#define RNG_REG_FROENABLE_MASK			0xffffff61#define RNG_REG_FRODETUNE_MASK			0xffffff62 63#define OMAP2_RNG_OUTPUT_SIZE			0x464#define OMAP4_RNG_OUTPUT_SIZE			0x865#define EIP76_RNG_OUTPUT_SIZE			0x1066 67/*68 * EIP76 RNG takes approx. 700us to produce 16 bytes of output data69 * as per testing results. And to account for the lack of udelay()'s70 * reliability, we keep the timeout as 1000us.71 */72#define RNG_DATA_FILL_TIMEOUT			10073 74enum {75	RNG_OUTPUT_0_REG = 0,76	RNG_OUTPUT_1_REG,77	RNG_OUTPUT_2_REG,78	RNG_OUTPUT_3_REG,79	RNG_STATUS_REG,80	RNG_INTMASK_REG,81	RNG_INTACK_REG,82	RNG_CONTROL_REG,83	RNG_CONFIG_REG,84	RNG_ALARMCNT_REG,85	RNG_FROENABLE_REG,86	RNG_FRODETUNE_REG,87	RNG_ALARMMASK_REG,88	RNG_ALARMSTOP_REG,89	RNG_REV_REG,90	RNG_SYSCONFIG_REG,91};92 93static const u16 reg_map_omap2[] = {94	[RNG_OUTPUT_0_REG]	= 0x0,95	[RNG_STATUS_REG]	= 0x4,96	[RNG_CONFIG_REG]	= 0x28,97	[RNG_REV_REG]		= 0x3c,98	[RNG_SYSCONFIG_REG]	= 0x40,99};100 101static const u16 reg_map_omap4[] = {102	[RNG_OUTPUT_0_REG]	= 0x0,103	[RNG_OUTPUT_1_REG]	= 0x4,104	[RNG_STATUS_REG]	= 0x8,105	[RNG_INTMASK_REG]	= 0xc,106	[RNG_INTACK_REG]	= 0x10,107	[RNG_CONTROL_REG]	= 0x14,108	[RNG_CONFIG_REG]	= 0x18,109	[RNG_ALARMCNT_REG]	= 0x1c,110	[RNG_FROENABLE_REG]	= 0x20,111	[RNG_FRODETUNE_REG]	= 0x24,112	[RNG_ALARMMASK_REG]	= 0x28,113	[RNG_ALARMSTOP_REG]	= 0x2c,114	[RNG_REV_REG]		= 0x1FE0,115	[RNG_SYSCONFIG_REG]	= 0x1FE4,116};117 118static const u16 reg_map_eip76[] = {119	[RNG_OUTPUT_0_REG]	= 0x0,120	[RNG_OUTPUT_1_REG]	= 0x4,121	[RNG_OUTPUT_2_REG]	= 0x8,122	[RNG_OUTPUT_3_REG]	= 0xc,123	[RNG_STATUS_REG]	= 0x10,124	[RNG_INTACK_REG]	= 0x10,125	[RNG_CONTROL_REG]	= 0x14,126	[RNG_CONFIG_REG]	= 0x18,127	[RNG_ALARMCNT_REG]	= 0x1c,128	[RNG_FROENABLE_REG]	= 0x20,129	[RNG_FRODETUNE_REG]	= 0x24,130	[RNG_ALARMMASK_REG]	= 0x28,131	[RNG_ALARMSTOP_REG]	= 0x2c,132	[RNG_REV_REG]		= 0x7c,133};134 135struct omap_rng_dev;136/**137 * struct omap_rng_pdata - RNG IP block-specific data138 * @regs: Pointer to the register offsets structure.139 * @data_size: No. of bytes in RNG output.140 * @data_present: Callback to determine if data is available.141 * @init: Callback for IP specific initialization sequence.142 * @cleanup: Callback for IP specific cleanup sequence.143 */144struct omap_rng_pdata {145	u16	*regs;146	u32	data_size;147	u32	(*data_present)(struct omap_rng_dev *priv);148	int	(*init)(struct omap_rng_dev *priv);149	void	(*cleanup)(struct omap_rng_dev *priv);150};151 152struct omap_rng_dev {153	void __iomem			*base;154	struct device			*dev;155	const struct omap_rng_pdata	*pdata;156	struct hwrng rng;157	struct clk 			*clk;158	struct clk			*clk_reg;159};160 161static inline u32 omap_rng_read(struct omap_rng_dev *priv, u16 reg)162{163	return __raw_readl(priv->base + priv->pdata->regs[reg]);164}165 166static inline void omap_rng_write(struct omap_rng_dev *priv, u16 reg,167				      u32 val)168{169	__raw_writel(val, priv->base + priv->pdata->regs[reg]);170}171 172 173static int omap_rng_do_read(struct hwrng *rng, void *data, size_t max,174			    bool wait)175{176	struct omap_rng_dev *priv;177	int i, present;178 179	priv = (struct omap_rng_dev *)rng->priv;180 181	if (max < priv->pdata->data_size)182		return 0;183 184	for (i = 0; i < RNG_DATA_FILL_TIMEOUT; i++) {185		present = priv->pdata->data_present(priv);186		if (present || !wait)187			break;188 189		udelay(10);190	}191	if (!present)192		return 0;193 194	memcpy_fromio(data, priv->base + priv->pdata->regs[RNG_OUTPUT_0_REG],195		      priv->pdata->data_size);196 197	if (priv->pdata->regs[RNG_INTACK_REG])198		omap_rng_write(priv, RNG_INTACK_REG, RNG_REG_INTACK_RDY_MASK);199 200	return priv->pdata->data_size;201}202 203static int omap_rng_init(struct hwrng *rng)204{205	struct omap_rng_dev *priv;206 207	priv = (struct omap_rng_dev *)rng->priv;208	return priv->pdata->init(priv);209}210 211static void omap_rng_cleanup(struct hwrng *rng)212{213	struct omap_rng_dev *priv;214 215	priv = (struct omap_rng_dev *)rng->priv;216	priv->pdata->cleanup(priv);217}218 219 220static inline u32 omap2_rng_data_present(struct omap_rng_dev *priv)221{222	return omap_rng_read(priv, RNG_STATUS_REG) ? 0 : 1;223}224 225static int omap2_rng_init(struct omap_rng_dev *priv)226{227	omap_rng_write(priv, RNG_SYSCONFIG_REG, 0x1);228	return 0;229}230 231static void omap2_rng_cleanup(struct omap_rng_dev *priv)232{233	omap_rng_write(priv, RNG_SYSCONFIG_REG, 0x0);234}235 236static struct omap_rng_pdata omap2_rng_pdata = {237	.regs		= (u16 *)reg_map_omap2,238	.data_size	= OMAP2_RNG_OUTPUT_SIZE,239	.data_present	= omap2_rng_data_present,240	.init		= omap2_rng_init,241	.cleanup	= omap2_rng_cleanup,242};243 244static inline u32 omap4_rng_data_present(struct omap_rng_dev *priv)245{246	return omap_rng_read(priv, RNG_STATUS_REG) & RNG_REG_STATUS_RDY;247}248 249static int eip76_rng_init(struct omap_rng_dev *priv)250{251	u32 val;252 253	/* Return if RNG is already running. */254	if (omap_rng_read(priv, RNG_CONTROL_REG) & RNG_CONTROL_ENABLE_TRNG_MASK)255		return 0;256 257	/*  Number of 512 bit blocks of raw Noise Source output data that must258	 *  be processed by either the Conditioning Function or the259	 *  SP 800-90 DRBG ‘BC_DF’ functionality to yield a ‘full entropy’260	 *  output value.261	 */262	val = 0x5 << RNG_CONFIG_MIN_REFIL_CYCLES_SHIFT;263 264	/* Number of FRO samples that are XOR-ed together into one bit to be265	 * shifted into the main shift register266	 */267	val |= RNG_CONFIG_MAX_REFIL_CYCLES << RNG_CONFIG_MAX_REFIL_CYCLES_SHIFT;268	omap_rng_write(priv, RNG_CONFIG_REG, val);269 270	/* Enable all available FROs */271	omap_rng_write(priv, RNG_FRODETUNE_REG, 0x0);272	omap_rng_write(priv, RNG_FROENABLE_REG, RNG_REG_FROENABLE_MASK);273 274	/* Enable TRNG */275	val = RNG_CONTROL_ENABLE_TRNG_MASK;276	omap_rng_write(priv, RNG_CONTROL_REG, val);277 278	return 0;279}280 281static int omap4_rng_init(struct omap_rng_dev *priv)282{283	u32 val;284 285	/* Return if RNG is already running. */286	if (omap_rng_read(priv, RNG_CONTROL_REG) & RNG_CONTROL_ENABLE_TRNG_MASK)287		return 0;288 289	val = RNG_CONFIG_MIN_REFIL_CYCLES << RNG_CONFIG_MIN_REFIL_CYCLES_SHIFT;290	val |= RNG_CONFIG_MAX_REFIL_CYCLES << RNG_CONFIG_MAX_REFIL_CYCLES_SHIFT;291	omap_rng_write(priv, RNG_CONFIG_REG, val);292 293	omap_rng_write(priv, RNG_FRODETUNE_REG, 0x0);294	omap_rng_write(priv, RNG_FROENABLE_REG, RNG_REG_FROENABLE_MASK);295	val = RNG_ALARM_THRESHOLD << RNG_ALARMCNT_ALARM_TH_SHIFT;296	val |= RNG_SHUTDOWN_THRESHOLD << RNG_ALARMCNT_SHUTDOWN_TH_SHIFT;297	omap_rng_write(priv, RNG_ALARMCNT_REG, val);298 299	val = RNG_CONTROL_STARTUP_CYCLES << RNG_CONTROL_STARTUP_CYCLES_SHIFT;300	val |= RNG_CONTROL_ENABLE_TRNG_MASK;301	omap_rng_write(priv, RNG_CONTROL_REG, val);302 303	return 0;304}305 306static void omap4_rng_cleanup(struct omap_rng_dev *priv)307{308	int val;309 310	val = omap_rng_read(priv, RNG_CONTROL_REG);311	val &= ~RNG_CONTROL_ENABLE_TRNG_MASK;312	omap_rng_write(priv, RNG_CONTROL_REG, val);313}314 315static irqreturn_t omap4_rng_irq(int irq, void *dev_id)316{317	struct omap_rng_dev *priv = dev_id;318	u32 fro_detune, fro_enable;319 320	/*321	 * Interrupt raised by a fro shutdown threshold, do the following:322	 * 1. Clear the alarm events.323	 * 2. De tune the FROs which are shutdown.324	 * 3. Re enable the shutdown FROs.325	 */326	omap_rng_write(priv, RNG_ALARMMASK_REG, 0x0);327	omap_rng_write(priv, RNG_ALARMSTOP_REG, 0x0);328 329	fro_enable = omap_rng_read(priv, RNG_FROENABLE_REG);330	fro_detune = ~fro_enable & RNG_REG_FRODETUNE_MASK;331	fro_detune = fro_detune | omap_rng_read(priv, RNG_FRODETUNE_REG);332	fro_enable = RNG_REG_FROENABLE_MASK;333 334	omap_rng_write(priv, RNG_FRODETUNE_REG, fro_detune);335	omap_rng_write(priv, RNG_FROENABLE_REG, fro_enable);336 337	omap_rng_write(priv, RNG_INTACK_REG, RNG_REG_INTACK_SHUTDOWN_OFLO_MASK);338 339	return IRQ_HANDLED;340}341 342static struct omap_rng_pdata omap4_rng_pdata = {343	.regs		= (u16 *)reg_map_omap4,344	.data_size	= OMAP4_RNG_OUTPUT_SIZE,345	.data_present	= omap4_rng_data_present,346	.init		= omap4_rng_init,347	.cleanup	= omap4_rng_cleanup,348};349 350static struct omap_rng_pdata eip76_rng_pdata = {351	.regs		= (u16 *)reg_map_eip76,352	.data_size	= EIP76_RNG_OUTPUT_SIZE,353	.data_present	= omap4_rng_data_present,354	.init		= eip76_rng_init,355	.cleanup	= omap4_rng_cleanup,356};357 358static const struct of_device_id omap_rng_of_match[] __maybe_unused = {359		{360			.compatible	= "ti,omap2-rng",361			.data		= &omap2_rng_pdata,362		},363		{364			.compatible	= "ti,omap4-rng",365			.data		= &omap4_rng_pdata,366		},367		{368			.compatible	= "inside-secure,safexcel-eip76",369			.data		= &eip76_rng_pdata,370		},371		{},372};373MODULE_DEVICE_TABLE(of, omap_rng_of_match);374 375static int of_get_omap_rng_device_details(struct omap_rng_dev *priv,376					  struct platform_device *pdev)377{378	struct device *dev = &pdev->dev;379	int irq, err;380 381	priv->pdata = of_device_get_match_data(dev);382	if (!priv->pdata)383		return -ENODEV;384 385 386	if (of_device_is_compatible(dev->of_node, "ti,omap4-rng") ||387	    of_device_is_compatible(dev->of_node, "inside-secure,safexcel-eip76")) {388		irq = platform_get_irq(pdev, 0);389		if (irq < 0)390			return irq;391 392		err = devm_request_irq(dev, irq, omap4_rng_irq,393				       IRQF_TRIGGER_NONE, dev_name(dev), priv);394		if (err) {395			dev_err(dev, "unable to request irq %d, err = %d\n",396				irq, err);397			return err;398		}399 400		/*401		 * On OMAP4, enabling the shutdown_oflo interrupt is402		 * done in the interrupt mask register. There is no403		 * such register on EIP76, and it's enabled by the404		 * same bit in the control register405		 */406		if (priv->pdata->regs[RNG_INTMASK_REG])407			omap_rng_write(priv, RNG_INTMASK_REG,408				       RNG_SHUTDOWN_OFLO_MASK);409		else410			omap_rng_write(priv, RNG_CONTROL_REG,411				       RNG_SHUTDOWN_OFLO_MASK);412	}413	return 0;414}415 416static int get_omap_rng_device_details(struct omap_rng_dev *omap_rng)417{418	/* Only OMAP2/3 can be non-DT */419	omap_rng->pdata = &omap2_rng_pdata;420	return 0;421}422 423static int omap_rng_probe(struct platform_device *pdev)424{425	struct omap_rng_dev *priv;426	struct device *dev = &pdev->dev;427	int ret;428 429	priv = devm_kzalloc(dev, sizeof(struct omap_rng_dev), GFP_KERNEL);430	if (!priv)431		return -ENOMEM;432 433	priv->rng.read = omap_rng_do_read;434	priv->rng.init = omap_rng_init;435	priv->rng.cleanup = omap_rng_cleanup;436	priv->rng.quality = 900;437 438	priv->rng.priv = (unsigned long)priv;439	platform_set_drvdata(pdev, priv);440	priv->dev = dev;441 442	priv->base = devm_platform_ioremap_resource(pdev, 0);443	if (IS_ERR(priv->base)) {444		ret = PTR_ERR(priv->base);445		goto err_ioremap;446	}447 448	priv->rng.name = devm_kstrdup(dev, dev_name(dev), GFP_KERNEL);449	if (!priv->rng.name) {450		ret = -ENOMEM;451		goto err_ioremap;452	}453 454	pm_runtime_enable(&pdev->dev);455	ret = pm_runtime_resume_and_get(&pdev->dev);456	if (ret < 0) {457		dev_err(&pdev->dev, "Failed to runtime_get device: %d\n", ret);458		goto err_ioremap;459	}460 461	priv->clk = devm_clk_get(&pdev->dev, NULL);462	if (PTR_ERR(priv->clk) == -EPROBE_DEFER)463		return -EPROBE_DEFER;464	if (!IS_ERR(priv->clk)) {465		ret = clk_prepare_enable(priv->clk);466		if (ret) {467			dev_err(&pdev->dev,468				"Unable to enable the clk: %d\n", ret);469			goto err_register;470		}471	}472 473	priv->clk_reg = devm_clk_get(&pdev->dev, "reg");474	if (PTR_ERR(priv->clk_reg) == -EPROBE_DEFER)475		return -EPROBE_DEFER;476	if (!IS_ERR(priv->clk_reg)) {477		ret = clk_prepare_enable(priv->clk_reg);478		if (ret) {479			dev_err(&pdev->dev,480				"Unable to enable the register clk: %d\n",481				ret);482			goto err_register;483		}484	}485 486	ret = (dev->of_node) ? of_get_omap_rng_device_details(priv, pdev) :487				get_omap_rng_device_details(priv);488	if (ret)489		goto err_register;490 491	ret = devm_hwrng_register(&pdev->dev, &priv->rng);492	if (ret)493		goto err_register;494 495	dev_info(&pdev->dev, "Random Number Generator ver. %02x\n",496		 omap_rng_read(priv, RNG_REV_REG));497 498	return 0;499 500err_register:501	priv->base = NULL;502	pm_runtime_put_sync(&pdev->dev);503	pm_runtime_disable(&pdev->dev);504 505	clk_disable_unprepare(priv->clk_reg);506	clk_disable_unprepare(priv->clk);507err_ioremap:508	dev_err(dev, "initialization failed.\n");509	return ret;510}511 512static void omap_rng_remove(struct platform_device *pdev)513{514	struct omap_rng_dev *priv = platform_get_drvdata(pdev);515 516 517	priv->pdata->cleanup(priv);518 519	pm_runtime_put_sync(&pdev->dev);520	pm_runtime_disable(&pdev->dev);521 522	clk_disable_unprepare(priv->clk);523	clk_disable_unprepare(priv->clk_reg);524}525 526static int __maybe_unused omap_rng_suspend(struct device *dev)527{528	struct omap_rng_dev *priv = dev_get_drvdata(dev);529 530	priv->pdata->cleanup(priv);531	pm_runtime_put_sync(dev);532 533	return 0;534}535 536static int __maybe_unused omap_rng_resume(struct device *dev)537{538	struct omap_rng_dev *priv = dev_get_drvdata(dev);539	int ret;540 541	ret = pm_runtime_resume_and_get(dev);542	if (ret < 0) {543		dev_err(dev, "Failed to runtime_get device: %d\n", ret);544		return ret;545	}546 547	priv->pdata->init(priv);548 549	return 0;550}551 552static SIMPLE_DEV_PM_OPS(omap_rng_pm, omap_rng_suspend, omap_rng_resume);553 554static struct platform_driver omap_rng_driver = {555	.driver = {556		.name		= "omap_rng",557		.pm		= &omap_rng_pm,558		.of_match_table = of_match_ptr(omap_rng_of_match),559	},560	.probe		= omap_rng_probe,561	.remove_new	= omap_rng_remove,562};563 564module_platform_driver(omap_rng_driver);565MODULE_ALIAS("platform:omap_rng");566MODULE_AUTHOR("Deepak Saxena (and others)");567MODULE_DESCRIPTION("RNG driver for TI OMAP CPU family");568MODULE_LICENSE("GPL");569