brintos

brintos / linux-shallow public Read only

0
0
Text · 14.6 KiB · 9d041a6 Raw
576 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (c) 2015, Daniel Thompson4 */5 6#include <linux/clk.h>7#include <linux/delay.h>8#include <linux/hw_random.h>9#include <linux/io.h>10#include <linux/iopoll.h>11#include <linux/kernel.h>12#include <linux/module.h>13#include <linux/of.h>14#include <linux/of_address.h>15#include <linux/platform_device.h>16#include <linux/pm_runtime.h>17#include <linux/reset.h>18#include <linux/slab.h>19 20#define RNG_CR			0x0021#define RNG_CR_RNGEN		BIT(2)22#define RNG_CR_CED		BIT(5)23#define RNG_CR_CONFIG1		GENMASK(11, 8)24#define RNG_CR_NISTC		BIT(12)25#define RNG_CR_CONFIG2		GENMASK(15, 13)26#define RNG_CR_CLKDIV_SHIFT	1627#define RNG_CR_CLKDIV		GENMASK(19, 16)28#define RNG_CR_CONFIG3		GENMASK(25, 20)29#define RNG_CR_CONDRST		BIT(30)30#define RNG_CR_CONFLOCK		BIT(31)31#define RNG_CR_ENTROPY_SRC_MASK	(RNG_CR_CONFIG1 | RNG_CR_NISTC | RNG_CR_CONFIG2 | RNG_CR_CONFIG3)32#define RNG_CR_CONFIG_MASK	(RNG_CR_ENTROPY_SRC_MASK | RNG_CR_CED | RNG_CR_CLKDIV)33 34#define RNG_SR			0x0435#define RNG_SR_DRDY		BIT(0)36#define RNG_SR_CECS		BIT(1)37#define RNG_SR_SECS		BIT(2)38#define RNG_SR_CEIS		BIT(5)39#define RNG_SR_SEIS		BIT(6)40 41#define RNG_DR			0x0842 43#define RNG_NSCR		0x0C44#define RNG_NSCR_MASK		GENMASK(17, 0)45 46#define RNG_HTCR		0x1047 48#define RNG_NB_RECOVER_TRIES	349 50struct stm32_rng_data {51	uint	max_clock_rate;52	u32	cr;53	u32	nscr;54	u32	htcr;55	bool	has_cond_reset;56};57 58/**59 * struct stm32_rng_config - RNG configuration data60 *61 * @cr:			RNG configuration. 0 means default hardware RNG configuration62 * @nscr:		Noise sources control configuration.63 * @htcr:		Health tests configuration.64 */65struct stm32_rng_config {66	u32 cr;67	u32 nscr;68	u32 htcr;69};70 71struct stm32_rng_private {72	struct hwrng rng;73	struct device *dev;74	void __iomem *base;75	struct clk *clk;76	struct reset_control *rst;77	struct stm32_rng_config pm_conf;78	const struct stm32_rng_data *data;79	bool ced;80	bool lock_conf;81};82 83/*84 * Extracts from the STM32 RNG specification when RNG supports CONDRST.85 *86 * When a noise source (or seed) error occurs, the RNG stops generating87 * random numbers and sets to “1” both SEIS and SECS bits to indicate88 * that a seed error occurred. (...)89 *90 * 1. Software reset by writing CONDRST at 1 and at 0 (see bitfield91 * description for details). This step is needed only if SECS is set.92 * Indeed, when SEIS is set and SECS is cleared it means RNG performed93 * the reset automatically (auto-reset).94 * 2. If SECS was set in step 1 (no auto-reset) wait for CONDRST95 * to be cleared in the RNG_CR register, then confirm that SEIS is96 * cleared in the RNG_SR register. Otherwise just clear SEIS bit in97 * the RNG_SR register.98 * 3. If SECS was set in step 1 (no auto-reset) wait for SECS to be99 * cleared by RNG. The random number generation is now back to normal.100 */101static int stm32_rng_conceal_seed_error_cond_reset(struct stm32_rng_private *priv)102{103	struct device *dev = priv->dev;104	u32 sr = readl_relaxed(priv->base + RNG_SR);105	u32 cr = readl_relaxed(priv->base + RNG_CR);106	int err;107 108	if (sr & RNG_SR_SECS) {109		/* Conceal by resetting the subsystem (step 1.) */110		writel_relaxed(cr | RNG_CR_CONDRST, priv->base + RNG_CR);111		writel_relaxed(cr & ~RNG_CR_CONDRST, priv->base + RNG_CR);112	} else {113		/* RNG auto-reset (step 2.) */114		writel_relaxed(sr & ~RNG_SR_SEIS, priv->base + RNG_SR);115		goto end;116	}117 118	err = readl_relaxed_poll_timeout_atomic(priv->base + RNG_CR, cr, !(cr & RNG_CR_CONDRST), 10,119						100000);120	if (err) {121		dev_err(dev, "%s: timeout %x\n", __func__, sr);122		return err;123	}124 125	/* Check SEIS is cleared (step 2.) */126	if (readl_relaxed(priv->base + RNG_SR) & RNG_SR_SEIS)127		return -EINVAL;128 129	err = readl_relaxed_poll_timeout_atomic(priv->base + RNG_SR, sr, !(sr & RNG_SR_SECS), 10,130						100000);131	if (err) {132		dev_err(dev, "%s: timeout %x\n", __func__, sr);133		return err;134	}135 136end:137	return 0;138}139 140/*141 * Extracts from the STM32 RNG specification, when CONDRST is not supported142 *143 * When a noise source (or seed) error occurs, the RNG stops generating144 * random numbers and sets to “1” both SEIS and SECS bits to indicate145 * that a seed error occurred. (...)146 *147 * The following sequence shall be used to fully recover from a seed148 * error after the RNG initialization:149 * 1. Clear the SEIS bit by writing it to “0”.150 * 2. Read out 12 words from the RNG_DR register, and discard each of151 * them in order to clean the pipeline.152 * 3. Confirm that SEIS is still cleared. Random number generation is153 * back to normal.154 */155static int stm32_rng_conceal_seed_error_sw_reset(struct stm32_rng_private *priv)156{157	unsigned int i = 0;158	u32 sr = readl_relaxed(priv->base + RNG_SR);159 160	writel_relaxed(sr & ~RNG_SR_SEIS, priv->base + RNG_SR);161 162	for (i = 12; i != 0; i--)163		(void)readl_relaxed(priv->base + RNG_DR);164 165	if (readl_relaxed(priv->base + RNG_SR) & RNG_SR_SEIS)166		return -EINVAL;167 168	return 0;169}170 171static int stm32_rng_conceal_seed_error(struct hwrng *rng)172{173	struct stm32_rng_private *priv = container_of(rng, struct stm32_rng_private, rng);174 175	dev_dbg(priv->dev, "Concealing seed error\n");176 177	if (priv->data->has_cond_reset)178		return stm32_rng_conceal_seed_error_cond_reset(priv);179	else180		return stm32_rng_conceal_seed_error_sw_reset(priv);181};182 183 184static int stm32_rng_read(struct hwrng *rng, void *data, size_t max, bool wait)185{186	struct stm32_rng_private *priv = container_of(rng, struct stm32_rng_private, rng);187	unsigned int i = 0;188	int retval = 0, err = 0;189	u32 sr;190 191	retval = pm_runtime_resume_and_get(priv->dev);192	if (retval)193		return retval;194 195	if (readl_relaxed(priv->base + RNG_SR) & RNG_SR_SEIS)196		stm32_rng_conceal_seed_error(rng);197 198	while (max >= sizeof(u32)) {199		sr = readl_relaxed(priv->base + RNG_SR);200		/*201		 * Manage timeout which is based on timer and take202		 * care of initial delay time when enabling the RNG.203		 */204		if (!sr && wait) {205			err = readl_relaxed_poll_timeout_atomic(priv->base206								   + RNG_SR,207								   sr, sr,208								   10, 50000);209			if (err) {210				dev_err(priv->dev, "%s: timeout %x!\n", __func__, sr);211				break;212			}213		} else if (!sr) {214			/* The FIFO is being filled up */215			break;216		}217 218		if (sr != RNG_SR_DRDY) {219			if (sr & RNG_SR_SEIS) {220				err = stm32_rng_conceal_seed_error(rng);221				i++;222				if (err && i > RNG_NB_RECOVER_TRIES) {223					dev_err(priv->dev, "Couldn't recover from seed error\n");224					retval = -ENOTRECOVERABLE;225					goto exit_rpm;226				}227 228				continue;229			}230 231			if (WARN_ONCE((sr & RNG_SR_CEIS), "RNG clock too slow - %x\n", sr))232				writel_relaxed(0, priv->base + RNG_SR);233		}234 235		/* Late seed error case: DR being 0 is an error status */236		*(u32 *)data = readl_relaxed(priv->base + RNG_DR);237		if (!*(u32 *)data) {238			err = stm32_rng_conceal_seed_error(rng);239			i++;240			if (err && i > RNG_NB_RECOVER_TRIES) {241				dev_err(priv->dev, "Couldn't recover from seed error");242				retval = -ENOTRECOVERABLE;243				goto exit_rpm;244			}245 246			continue;247		}248 249		i = 0;250		retval += sizeof(u32);251		data += sizeof(u32);252		max -= sizeof(u32);253	}254 255exit_rpm:256	pm_runtime_mark_last_busy(priv->dev);257	pm_runtime_put_sync_autosuspend(priv->dev);258 259	return retval || !wait ? retval : -EIO;260}261 262static uint stm32_rng_clock_freq_restrain(struct hwrng *rng)263{264	struct stm32_rng_private *priv =265	    container_of(rng, struct stm32_rng_private, rng);266	unsigned long clock_rate = 0;267	uint clock_div = 0;268 269	clock_rate = clk_get_rate(priv->clk);270 271	/*272	 * Get the exponent to apply on the CLKDIV field in RNG_CR register273	 * No need to handle the case when clock-div > 0xF as it is physically274	 * impossible275	 */276	while ((clock_rate >> clock_div) > priv->data->max_clock_rate)277		clock_div++;278 279	pr_debug("RNG clk rate : %lu\n", clk_get_rate(priv->clk) >> clock_div);280 281	return clock_div;282}283 284static int stm32_rng_init(struct hwrng *rng)285{286	struct stm32_rng_private *priv =287	    container_of(rng, struct stm32_rng_private, rng);288	int err;289	u32 reg;290 291	err = clk_prepare_enable(priv->clk);292	if (err)293		return err;294 295	/* clear error indicators */296	writel_relaxed(0, priv->base + RNG_SR);297 298	reg = readl_relaxed(priv->base + RNG_CR);299 300	/*301	 * Keep default RNG configuration if none was specified.302	 * 0 is an invalid value as it disables all entropy sources.303	 */304	if (priv->data->has_cond_reset && priv->data->cr) {305		uint clock_div = stm32_rng_clock_freq_restrain(rng);306 307		reg &= ~RNG_CR_CONFIG_MASK;308		reg |= RNG_CR_CONDRST | (priv->data->cr & RNG_CR_ENTROPY_SRC_MASK) |309		       (clock_div << RNG_CR_CLKDIV_SHIFT);310		if (priv->ced)311			reg &= ~RNG_CR_CED;312		else313			reg |= RNG_CR_CED;314		writel_relaxed(reg, priv->base + RNG_CR);315 316		/* Health tests and noise control registers */317		writel_relaxed(priv->data->htcr, priv->base + RNG_HTCR);318		writel_relaxed(priv->data->nscr & RNG_NSCR_MASK, priv->base + RNG_NSCR);319 320		reg &= ~RNG_CR_CONDRST;321		reg |= RNG_CR_RNGEN;322		if (priv->lock_conf)323			reg |= RNG_CR_CONFLOCK;324 325		writel_relaxed(reg, priv->base + RNG_CR);326 327		err = readl_relaxed_poll_timeout_atomic(priv->base + RNG_CR, reg,328							(!(reg & RNG_CR_CONDRST)),329							10, 50000);330		if (err) {331			clk_disable_unprepare(priv->clk);332			dev_err(priv->dev, "%s: timeout %x!\n", __func__, reg);333			return -EINVAL;334		}335	} else {336		/* Handle all RNG versions by checking if conditional reset should be set */337		if (priv->data->has_cond_reset)338			reg |= RNG_CR_CONDRST;339 340		if (priv->ced)341			reg &= ~RNG_CR_CED;342		else343			reg |= RNG_CR_CED;344 345		writel_relaxed(reg, priv->base + RNG_CR);346 347		if (priv->data->has_cond_reset)348			reg &= ~RNG_CR_CONDRST;349 350		reg |= RNG_CR_RNGEN;351 352		writel_relaxed(reg, priv->base + RNG_CR);353	}354 355	err = readl_relaxed_poll_timeout_atomic(priv->base + RNG_SR, reg,356						reg & RNG_SR_DRDY,357						10, 100000);358	if (err || (reg & ~RNG_SR_DRDY)) {359		clk_disable_unprepare(priv->clk);360		dev_err(priv->dev, "%s: timeout:%x SR: %x!\n", __func__, err, reg);361		return -EINVAL;362	}363 364	clk_disable_unprepare(priv->clk);365 366	return 0;367}368 369static void stm32_rng_remove(struct platform_device *ofdev)370{371	pm_runtime_disable(&ofdev->dev);372}373 374static int __maybe_unused stm32_rng_runtime_suspend(struct device *dev)375{376	struct stm32_rng_private *priv = dev_get_drvdata(dev);377	u32 reg;378 379	reg = readl_relaxed(priv->base + RNG_CR);380	reg &= ~RNG_CR_RNGEN;381	writel_relaxed(reg, priv->base + RNG_CR);382	clk_disable_unprepare(priv->clk);383 384	return 0;385}386 387static int __maybe_unused stm32_rng_suspend(struct device *dev)388{389	struct stm32_rng_private *priv = dev_get_drvdata(dev);390	int err;391 392	err = clk_prepare_enable(priv->clk);393	if (err)394		return err;395 396	if (priv->data->has_cond_reset) {397		priv->pm_conf.nscr = readl_relaxed(priv->base + RNG_NSCR);398		priv->pm_conf.htcr = readl_relaxed(priv->base + RNG_HTCR);399	}400 401	/* Do not save that RNG is enabled as it will be handled at resume */402	priv->pm_conf.cr = readl_relaxed(priv->base + RNG_CR) & ~RNG_CR_RNGEN;403 404	writel_relaxed(priv->pm_conf.cr, priv->base + RNG_CR);405 406	clk_disable_unprepare(priv->clk);407 408	return 0;409}410 411static int __maybe_unused stm32_rng_runtime_resume(struct device *dev)412{413	struct stm32_rng_private *priv = dev_get_drvdata(dev);414	int err;415	u32 reg;416 417	err = clk_prepare_enable(priv->clk);418	if (err)419		return err;420 421	/* Clean error indications */422	writel_relaxed(0, priv->base + RNG_SR);423 424	reg = readl_relaxed(priv->base + RNG_CR);425	reg |= RNG_CR_RNGEN;426	writel_relaxed(reg, priv->base + RNG_CR);427 428	return 0;429}430 431static int __maybe_unused stm32_rng_resume(struct device *dev)432{433	struct stm32_rng_private *priv = dev_get_drvdata(dev);434	int err;435	u32 reg;436 437	err = clk_prepare_enable(priv->clk);438	if (err)439		return err;440 441	/* Clean error indications */442	writel_relaxed(0, priv->base + RNG_SR);443 444	if (priv->data->has_cond_reset) {445		/*446		 * Correct configuration in bits [29:4] must be set in the same447		 * access that set RNG_CR_CONDRST bit. Else config setting is448		 * not taken into account. CONFIGLOCK bit must also be unset but449		 * it is not handled at the moment.450		 */451		writel_relaxed(priv->pm_conf.cr | RNG_CR_CONDRST, priv->base + RNG_CR);452 453		writel_relaxed(priv->pm_conf.nscr, priv->base + RNG_NSCR);454		writel_relaxed(priv->pm_conf.htcr, priv->base + RNG_HTCR);455 456		reg = readl_relaxed(priv->base + RNG_CR);457		reg |= RNG_CR_RNGEN;458		reg &= ~RNG_CR_CONDRST;459		writel_relaxed(reg, priv->base + RNG_CR);460 461		err = readl_relaxed_poll_timeout_atomic(priv->base + RNG_CR, reg,462							reg & ~RNG_CR_CONDRST, 10, 100000);463 464		if (err) {465			clk_disable_unprepare(priv->clk);466			dev_err(priv->dev, "%s: timeout:%x CR: %x!\n", __func__, err, reg);467			return -EINVAL;468		}469	} else {470		reg = priv->pm_conf.cr;471		reg |= RNG_CR_RNGEN;472		writel_relaxed(reg, priv->base + RNG_CR);473	}474 475	clk_disable_unprepare(priv->clk);476 477	return 0;478}479 480static const struct dev_pm_ops __maybe_unused stm32_rng_pm_ops = {481	SET_RUNTIME_PM_OPS(stm32_rng_runtime_suspend,482			   stm32_rng_runtime_resume, NULL)483	SET_SYSTEM_SLEEP_PM_OPS(stm32_rng_suspend,484				stm32_rng_resume)485};486 487static const struct stm32_rng_data stm32mp13_rng_data = {488	.has_cond_reset = true,489	.max_clock_rate = 48000000,490	.cr = 0x00F00D00,491	.nscr = 0x2B5BB,492	.htcr = 0x969D,493};494 495static const struct stm32_rng_data stm32_rng_data = {496	.has_cond_reset = false,497	.max_clock_rate = 3000000,498};499 500static const struct of_device_id stm32_rng_match[] = {501	{502		.compatible = "st,stm32mp13-rng",503		.data = &stm32mp13_rng_data,504	},505	{506		.compatible = "st,stm32-rng",507		.data = &stm32_rng_data,508	},509	{},510};511MODULE_DEVICE_TABLE(of, stm32_rng_match);512 513static int stm32_rng_probe(struct platform_device *ofdev)514{515	struct device *dev = &ofdev->dev;516	struct device_node *np = ofdev->dev.of_node;517	struct stm32_rng_private *priv;518	struct resource *res;519 520	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);521	if (!priv)522		return -ENOMEM;523 524	priv->base = devm_platform_get_and_ioremap_resource(ofdev, 0, &res);525	if (IS_ERR(priv->base))526		return PTR_ERR(priv->base);527 528	priv->clk = devm_clk_get(&ofdev->dev, NULL);529	if (IS_ERR(priv->clk))530		return PTR_ERR(priv->clk);531 532	priv->rst = devm_reset_control_get(&ofdev->dev, NULL);533	if (!IS_ERR(priv->rst)) {534		reset_control_assert(priv->rst);535		udelay(2);536		reset_control_deassert(priv->rst);537	}538 539	priv->ced = of_property_read_bool(np, "clock-error-detect");540	priv->lock_conf = of_property_read_bool(np, "st,rng-lock-conf");541	priv->dev = dev;542 543	priv->data = of_device_get_match_data(dev);544	if (!priv->data)545		return -ENODEV;546 547	dev_set_drvdata(dev, priv);548 549	priv->rng.name = dev_driver_string(dev);550	priv->rng.init = stm32_rng_init;551	priv->rng.read = stm32_rng_read;552	priv->rng.quality = 900;553 554	pm_runtime_set_autosuspend_delay(dev, 100);555	pm_runtime_use_autosuspend(dev);556	pm_runtime_enable(dev);557 558	return devm_hwrng_register(dev, &priv->rng);559}560 561static struct platform_driver stm32_rng_driver = {562	.driver = {563		.name = "stm32-rng",564		.pm = pm_ptr(&stm32_rng_pm_ops),565		.of_match_table = stm32_rng_match,566	},567	.probe = stm32_rng_probe,568	.remove_new = stm32_rng_remove,569};570 571module_platform_driver(stm32_rng_driver);572 573MODULE_LICENSE("GPL");574MODULE_AUTHOR("Daniel Thompson <daniel.thompson@linaro.org>");575MODULE_DESCRIPTION("STMicroelectronics STM32 RNG device driver");576