brintos

brintos / linux-shallow public Read only

0
0
Text · 10.5 KiB · 642d135 Raw
389 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * APM X-Gene SoC RNG Driver4 *5 * Copyright (c) 2014, Applied Micro Circuits Corporation6 * Author: Rameshwar Prasad Sahu <rsahu@apm.com>7 *	   Shamal Winchurkar <swinchurkar@apm.com>8 *	   Feng Kan <fkan@apm.com>9 */10 11#include <linux/acpi.h>12#include <linux/clk.h>13#include <linux/delay.h>14#include <linux/hw_random.h>15#include <linux/init.h>16#include <linux/interrupt.h>17#include <linux/io.h>18#include <linux/module.h>19#include <linux/mod_devicetable.h>20#include <linux/platform_device.h>21#include <linux/timer.h>22 23#define RNG_MAX_DATUM			424#define MAX_TRY				10025#define XGENE_RNG_RETRY_COUNT		2026#define XGENE_RNG_RETRY_INTERVAL	1027 28/* RNG  Registers */29#define RNG_INOUT_0			0x0030#define RNG_INTR_STS_ACK		0x1031#define RNG_CONTROL			0x1432#define RNG_CONFIG			0x1833#define RNG_ALARMCNT			0x1c34#define RNG_FROENABLE			0x2035#define RNG_FRODETUNE			0x2436#define RNG_ALARMMASK			0x2837#define RNG_ALARMSTOP			0x2c38#define RNG_OPTIONS			0x7839#define RNG_EIP_REV			0x7c40 41#define MONOBIT_FAIL_MASK		BIT(7)42#define POKER_FAIL_MASK			BIT(6)43#define LONG_RUN_FAIL_MASK		BIT(5)44#define RUN_FAIL_MASK			BIT(4)45#define NOISE_FAIL_MASK			BIT(3)46#define STUCK_OUT_MASK			BIT(2)47#define SHUTDOWN_OFLO_MASK		BIT(1)48#define READY_MASK			BIT(0)49 50#define MAJOR_HW_REV_RD(src)		(((src) & 0x0f000000) >> 24)51#define MINOR_HW_REV_RD(src)		(((src) & 0x00f00000) >> 20)52#define HW_PATCH_LEVEL_RD(src)		(((src) & 0x000f0000) >> 16)53#define MAX_REFILL_CYCLES_SET(dst, src) \54			((dst & ~0xffff0000) | (((u32)src << 16) & 0xffff0000))55#define MIN_REFILL_CYCLES_SET(dst, src) \56			((dst & ~0x000000ff) | (((u32)src) & 0x000000ff))57#define ALARM_THRESHOLD_SET(dst, src) \58			((dst & ~0x000000ff) | (((u32)src) & 0x000000ff))59#define ENABLE_RNG_SET(dst, src) \60			((dst & ~BIT(10)) | (((u32)src << 10) & BIT(10)))61#define REGSPEC_TEST_MODE_SET(dst, src) \62			((dst & ~BIT(8)) | (((u32)src << 8) & BIT(8)))63#define MONOBIT_FAIL_MASK_SET(dst, src) \64			((dst & ~BIT(7)) | (((u32)src << 7) & BIT(7)))65#define POKER_FAIL_MASK_SET(dst, src) \66			((dst & ~BIT(6)) | (((u32)src << 6) & BIT(6)))67#define LONG_RUN_FAIL_MASK_SET(dst, src) \68			((dst & ~BIT(5)) | (((u32)src << 5) & BIT(5)))69#define RUN_FAIL_MASK_SET(dst, src) \70			((dst & ~BIT(4)) | (((u32)src << 4) & BIT(4)))71#define NOISE_FAIL_MASK_SET(dst, src) \72			((dst & ~BIT(3)) | (((u32)src << 3) & BIT(3)))73#define STUCK_OUT_MASK_SET(dst, src) \74			((dst & ~BIT(2)) | (((u32)src << 2) & BIT(2)))75#define SHUTDOWN_OFLO_MASK_SET(dst, src) \76			((dst & ~BIT(1)) | (((u32)src << 1) & BIT(1)))77 78struct xgene_rng_dev {79	u32 irq;80	void  __iomem *csr_base;81	u32 revision;82	u32 datum_size;83	u32 failure_cnt;	/* Failure count last minute */84	unsigned long failure_ts;/* First failure timestamp */85	struct timer_list failure_timer;86	struct device *dev;87};88 89static void xgene_rng_expired_timer(struct timer_list *t)90{91	struct xgene_rng_dev *ctx = from_timer(ctx, t, failure_timer);92 93	/* Clear failure counter as timer expired */94	disable_irq(ctx->irq);95	ctx->failure_cnt = 0;96	del_timer(&ctx->failure_timer);97	enable_irq(ctx->irq);98}99 100static void xgene_rng_start_timer(struct xgene_rng_dev *ctx)101{102	ctx->failure_timer.expires = jiffies + 120 * HZ;103	add_timer(&ctx->failure_timer);104}105 106/*107 * Initialize or reinit free running oscillators (FROs)108 */109static void xgene_rng_init_fro(struct xgene_rng_dev *ctx, u32 fro_val)110{111	writel(fro_val, ctx->csr_base + RNG_FRODETUNE);112	writel(0x00000000, ctx->csr_base + RNG_ALARMMASK);113	writel(0x00000000, ctx->csr_base + RNG_ALARMSTOP);114	writel(0xFFFFFFFF, ctx->csr_base + RNG_FROENABLE);115}116 117static void xgene_rng_chk_overflow(struct xgene_rng_dev *ctx)118{119	u32 val;120 121	val = readl(ctx->csr_base + RNG_INTR_STS_ACK);122	if (val & MONOBIT_FAIL_MASK)123		/*124		 * LFSR detected an out-of-bounds number of 1s after125		 * checking 20,000 bits (test T1 as specified in the126		 * AIS-31 standard)127		 */128		dev_err(ctx->dev, "test monobit failure error 0x%08X\n", val);129	if (val & POKER_FAIL_MASK)130		/*131		 * LFSR detected an out-of-bounds value in at least one132		 * of the 16 poker_count_X counters or an out of bounds sum133		 * of squares value after checking 20,000 bits (test T2 as134		 * specified in the AIS-31 standard)135		 */136		dev_err(ctx->dev, "test poker failure error 0x%08X\n", val);137	if (val & LONG_RUN_FAIL_MASK)138		/*139		 * LFSR detected a sequence of 34 identical bits140		 * (test T4 as specified in the AIS-31 standard)141		 */142		dev_err(ctx->dev, "test long run failure error 0x%08X\n", val);143	if (val & RUN_FAIL_MASK)144		/*145		 * LFSR detected an outof-bounds value for at least one146		 * of the running counters after checking 20,000 bits147		 * (test T3 as specified in the AIS-31 standard)148		 */149		dev_err(ctx->dev, "test run failure error 0x%08X\n", val);150	if (val & NOISE_FAIL_MASK)151		/* LFSR detected a sequence of 48 identical bits */152		dev_err(ctx->dev, "noise failure error 0x%08X\n", val);153	if (val & STUCK_OUT_MASK)154		/*155		 * Detected output data registers generated same value twice156		 * in a row157		 */158		dev_err(ctx->dev, "stuck out failure error 0x%08X\n", val);159 160	if (val & SHUTDOWN_OFLO_MASK) {161		u32 frostopped;162 163		/* FROs shut down after a second error event. Try recover. */164		if (++ctx->failure_cnt == 1) {165			/* 1st time, just recover */166			ctx->failure_ts = jiffies;167			frostopped = readl(ctx->csr_base + RNG_ALARMSTOP);168			xgene_rng_init_fro(ctx, frostopped);169 170			/*171			 * We must start a timer to clear out this error172			 * in case the system timer wrap around173			 */174			xgene_rng_start_timer(ctx);175		} else {176			/* 2nd time failure in lesser than 1 minute? */177			if (time_after(ctx->failure_ts + 60 * HZ, jiffies)) {178				dev_err(ctx->dev,179					"FRO shutdown failure error 0x%08X\n",180					val);181			} else {182				/* 2nd time failure after 1 minutes, recover */183				ctx->failure_ts = jiffies;184				ctx->failure_cnt = 1;185				/*186				 * We must start a timer to clear out this187				 * error in case the system timer wrap188				 * around189				 */190				xgene_rng_start_timer(ctx);191			}192			frostopped = readl(ctx->csr_base + RNG_ALARMSTOP);193			xgene_rng_init_fro(ctx, frostopped);194		}195	}196	/* Clear them all */197	writel(val, ctx->csr_base + RNG_INTR_STS_ACK);198}199 200static irqreturn_t xgene_rng_irq_handler(int irq, void *id)201{202	struct xgene_rng_dev *ctx = id;203 204	/* RNG Alarm Counter overflow */205	xgene_rng_chk_overflow(ctx);206 207	return IRQ_HANDLED;208}209 210static int xgene_rng_data_present(struct hwrng *rng, int wait)211{212	struct xgene_rng_dev *ctx = (struct xgene_rng_dev *) rng->priv;213	u32 i, val = 0;214 215	for (i = 0; i < XGENE_RNG_RETRY_COUNT; i++) {216		val = readl(ctx->csr_base + RNG_INTR_STS_ACK);217		if ((val & READY_MASK) || !wait)218			break;219		udelay(XGENE_RNG_RETRY_INTERVAL);220	}221 222	return (val & READY_MASK);223}224 225static int xgene_rng_data_read(struct hwrng *rng, u32 *data)226{227	struct xgene_rng_dev *ctx = (struct xgene_rng_dev *) rng->priv;228	int i;229 230	for (i = 0; i < ctx->datum_size; i++)231		data[i] = readl(ctx->csr_base + RNG_INOUT_0 + i * 4);232 233	/* Clear ready bit to start next transaction */234	writel(READY_MASK, ctx->csr_base + RNG_INTR_STS_ACK);235 236	return ctx->datum_size << 2;237}238 239static void xgene_rng_init_internal(struct xgene_rng_dev *ctx)240{241	u32 val;242 243	writel(0x00000000, ctx->csr_base + RNG_CONTROL);244 245	val = MAX_REFILL_CYCLES_SET(0, 10);246	val = MIN_REFILL_CYCLES_SET(val, 10);247	writel(val, ctx->csr_base + RNG_CONFIG);248 249	val = ALARM_THRESHOLD_SET(0, 0xFF);250	writel(val, ctx->csr_base + RNG_ALARMCNT);251 252	xgene_rng_init_fro(ctx, 0);253 254	writel(MONOBIT_FAIL_MASK |255		POKER_FAIL_MASK	|256		LONG_RUN_FAIL_MASK |257		RUN_FAIL_MASK |258		NOISE_FAIL_MASK |259		STUCK_OUT_MASK |260		SHUTDOWN_OFLO_MASK |261		READY_MASK, ctx->csr_base + RNG_INTR_STS_ACK);262 263	val = ENABLE_RNG_SET(0, 1);264	val = MONOBIT_FAIL_MASK_SET(val, 1);265	val = POKER_FAIL_MASK_SET(val, 1);266	val = LONG_RUN_FAIL_MASK_SET(val, 1);267	val = RUN_FAIL_MASK_SET(val, 1);268	val = NOISE_FAIL_MASK_SET(val, 1);269	val = STUCK_OUT_MASK_SET(val, 1);270	val = SHUTDOWN_OFLO_MASK_SET(val, 1);271	writel(val, ctx->csr_base + RNG_CONTROL);272}273 274static int xgene_rng_init(struct hwrng *rng)275{276	struct xgene_rng_dev *ctx = (struct xgene_rng_dev *) rng->priv;277 278	ctx->failure_cnt = 0;279	timer_setup(&ctx->failure_timer, xgene_rng_expired_timer, 0);280 281	ctx->revision = readl(ctx->csr_base + RNG_EIP_REV);282 283	dev_dbg(ctx->dev, "Rev %d.%d.%d\n",284		MAJOR_HW_REV_RD(ctx->revision),285		MINOR_HW_REV_RD(ctx->revision),286		HW_PATCH_LEVEL_RD(ctx->revision));287 288	dev_dbg(ctx->dev, "Options 0x%08X",289		readl(ctx->csr_base + RNG_OPTIONS));290 291	xgene_rng_init_internal(ctx);292 293	ctx->datum_size = RNG_MAX_DATUM;294 295	return 0;296}297 298#ifdef CONFIG_ACPI299static const struct acpi_device_id xgene_rng_acpi_match[] = {300	{ "APMC0D18", },301	{ }302};303MODULE_DEVICE_TABLE(acpi, xgene_rng_acpi_match);304#endif305 306static struct hwrng xgene_rng_func = {307	.name		= "xgene-rng",308	.init		= xgene_rng_init,309	.data_present	= xgene_rng_data_present,310	.data_read	= xgene_rng_data_read,311};312 313static int xgene_rng_probe(struct platform_device *pdev)314{315	struct xgene_rng_dev *ctx;316	struct clk *clk;317	int rc = 0;318 319	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);320	if (!ctx)321		return -ENOMEM;322 323	ctx->dev = &pdev->dev;324 325	ctx->csr_base = devm_platform_ioremap_resource(pdev, 0);326	if (IS_ERR(ctx->csr_base))327		return PTR_ERR(ctx->csr_base);328 329	rc = platform_get_irq(pdev, 0);330	if (rc < 0)331		return rc;332	ctx->irq = rc;333 334	dev_dbg(&pdev->dev, "APM X-Gene RNG BASE %p ALARM IRQ %d",335		ctx->csr_base, ctx->irq);336 337	rc = devm_request_irq(&pdev->dev, ctx->irq, xgene_rng_irq_handler, 0,338				dev_name(&pdev->dev), ctx);339	if (rc)340		return dev_err_probe(&pdev->dev, rc, "Could not request RNG alarm IRQ\n");341 342	/* Enable IP clock */343	clk = devm_clk_get_optional_enabled(&pdev->dev, NULL);344	if (IS_ERR(clk))345		return dev_err_probe(&pdev->dev, PTR_ERR(clk), "Couldn't get the clock for RNG\n");346 347	xgene_rng_func.priv = (unsigned long) ctx;348 349	rc = devm_hwrng_register(&pdev->dev, &xgene_rng_func);350	if (rc)351		return dev_err_probe(&pdev->dev, rc, "RNG registering failed\n");352 353	rc = device_init_wakeup(&pdev->dev, 1);354	if (rc)355		return dev_err_probe(&pdev->dev, rc, "RNG device_init_wakeup failed\n");356 357	return 0;358}359 360static void xgene_rng_remove(struct platform_device *pdev)361{362	int rc;363 364	rc = device_init_wakeup(&pdev->dev, 0);365	if (rc)366		dev_err(&pdev->dev, "RNG init wakeup failed error %d\n", rc);367}368 369static const struct of_device_id xgene_rng_of_match[] = {370	{ .compatible = "apm,xgene-rng" },371	{ }372};373 374MODULE_DEVICE_TABLE(of, xgene_rng_of_match);375 376static struct platform_driver xgene_rng_driver = {377	.probe = xgene_rng_probe,378	.remove_new = xgene_rng_remove,379	.driver = {380		.name		= "xgene-rng",381		.of_match_table = xgene_rng_of_match,382		.acpi_match_table = ACPI_PTR(xgene_rng_acpi_match),383	},384};385 386module_platform_driver(xgene_rng_driver);387MODULE_DESCRIPTION("APM X-Gene RNG driver");388MODULE_LICENSE("GPL");389