162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * APM X-Gene SoC RNG Driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2014, Applied Micro Circuits Corporation 662306a36Sopenharmony_ci * Author: Rameshwar Prasad Sahu <rsahu@apm.com> 762306a36Sopenharmony_ci * Shamal Winchurkar <swinchurkar@apm.com> 862306a36Sopenharmony_ci * Feng Kan <fkan@apm.com> 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/acpi.h> 1262306a36Sopenharmony_ci#include <linux/clk.h> 1362306a36Sopenharmony_ci#include <linux/delay.h> 1462306a36Sopenharmony_ci#include <linux/hw_random.h> 1562306a36Sopenharmony_ci#include <linux/init.h> 1662306a36Sopenharmony_ci#include <linux/interrupt.h> 1762306a36Sopenharmony_ci#include <linux/io.h> 1862306a36Sopenharmony_ci#include <linux/module.h> 1962306a36Sopenharmony_ci#include <linux/mod_devicetable.h> 2062306a36Sopenharmony_ci#include <linux/platform_device.h> 2162306a36Sopenharmony_ci#include <linux/timer.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define RNG_MAX_DATUM 4 2462306a36Sopenharmony_ci#define MAX_TRY 100 2562306a36Sopenharmony_ci#define XGENE_RNG_RETRY_COUNT 20 2662306a36Sopenharmony_ci#define XGENE_RNG_RETRY_INTERVAL 10 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* RNG Registers */ 2962306a36Sopenharmony_ci#define RNG_INOUT_0 0x00 3062306a36Sopenharmony_ci#define RNG_INTR_STS_ACK 0x10 3162306a36Sopenharmony_ci#define RNG_CONTROL 0x14 3262306a36Sopenharmony_ci#define RNG_CONFIG 0x18 3362306a36Sopenharmony_ci#define RNG_ALARMCNT 0x1c 3462306a36Sopenharmony_ci#define RNG_FROENABLE 0x20 3562306a36Sopenharmony_ci#define RNG_FRODETUNE 0x24 3662306a36Sopenharmony_ci#define RNG_ALARMMASK 0x28 3762306a36Sopenharmony_ci#define RNG_ALARMSTOP 0x2c 3862306a36Sopenharmony_ci#define RNG_OPTIONS 0x78 3962306a36Sopenharmony_ci#define RNG_EIP_REV 0x7c 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#define MONOBIT_FAIL_MASK BIT(7) 4262306a36Sopenharmony_ci#define POKER_FAIL_MASK BIT(6) 4362306a36Sopenharmony_ci#define LONG_RUN_FAIL_MASK BIT(5) 4462306a36Sopenharmony_ci#define RUN_FAIL_MASK BIT(4) 4562306a36Sopenharmony_ci#define NOISE_FAIL_MASK BIT(3) 4662306a36Sopenharmony_ci#define STUCK_OUT_MASK BIT(2) 4762306a36Sopenharmony_ci#define SHUTDOWN_OFLO_MASK BIT(1) 4862306a36Sopenharmony_ci#define READY_MASK BIT(0) 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#define MAJOR_HW_REV_RD(src) (((src) & 0x0f000000) >> 24) 5162306a36Sopenharmony_ci#define MINOR_HW_REV_RD(src) (((src) & 0x00f00000) >> 20) 5262306a36Sopenharmony_ci#define HW_PATCH_LEVEL_RD(src) (((src) & 0x000f0000) >> 16) 5362306a36Sopenharmony_ci#define MAX_REFILL_CYCLES_SET(dst, src) \ 5462306a36Sopenharmony_ci ((dst & ~0xffff0000) | (((u32)src << 16) & 0xffff0000)) 5562306a36Sopenharmony_ci#define MIN_REFILL_CYCLES_SET(dst, src) \ 5662306a36Sopenharmony_ci ((dst & ~0x000000ff) | (((u32)src) & 0x000000ff)) 5762306a36Sopenharmony_ci#define ALARM_THRESHOLD_SET(dst, src) \ 5862306a36Sopenharmony_ci ((dst & ~0x000000ff) | (((u32)src) & 0x000000ff)) 5962306a36Sopenharmony_ci#define ENABLE_RNG_SET(dst, src) \ 6062306a36Sopenharmony_ci ((dst & ~BIT(10)) | (((u32)src << 10) & BIT(10))) 6162306a36Sopenharmony_ci#define REGSPEC_TEST_MODE_SET(dst, src) \ 6262306a36Sopenharmony_ci ((dst & ~BIT(8)) | (((u32)src << 8) & BIT(8))) 6362306a36Sopenharmony_ci#define MONOBIT_FAIL_MASK_SET(dst, src) \ 6462306a36Sopenharmony_ci ((dst & ~BIT(7)) | (((u32)src << 7) & BIT(7))) 6562306a36Sopenharmony_ci#define POKER_FAIL_MASK_SET(dst, src) \ 6662306a36Sopenharmony_ci ((dst & ~BIT(6)) | (((u32)src << 6) & BIT(6))) 6762306a36Sopenharmony_ci#define LONG_RUN_FAIL_MASK_SET(dst, src) \ 6862306a36Sopenharmony_ci ((dst & ~BIT(5)) | (((u32)src << 5) & BIT(5))) 6962306a36Sopenharmony_ci#define RUN_FAIL_MASK_SET(dst, src) \ 7062306a36Sopenharmony_ci ((dst & ~BIT(4)) | (((u32)src << 4) & BIT(4))) 7162306a36Sopenharmony_ci#define NOISE_FAIL_MASK_SET(dst, src) \ 7262306a36Sopenharmony_ci ((dst & ~BIT(3)) | (((u32)src << 3) & BIT(3))) 7362306a36Sopenharmony_ci#define STUCK_OUT_MASK_SET(dst, src) \ 7462306a36Sopenharmony_ci ((dst & ~BIT(2)) | (((u32)src << 2) & BIT(2))) 7562306a36Sopenharmony_ci#define SHUTDOWN_OFLO_MASK_SET(dst, src) \ 7662306a36Sopenharmony_ci ((dst & ~BIT(1)) | (((u32)src << 1) & BIT(1))) 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistruct xgene_rng_dev { 7962306a36Sopenharmony_ci u32 irq; 8062306a36Sopenharmony_ci void __iomem *csr_base; 8162306a36Sopenharmony_ci u32 revision; 8262306a36Sopenharmony_ci u32 datum_size; 8362306a36Sopenharmony_ci u32 failure_cnt; /* Failure count last minute */ 8462306a36Sopenharmony_ci unsigned long failure_ts;/* First failure timestamp */ 8562306a36Sopenharmony_ci struct timer_list failure_timer; 8662306a36Sopenharmony_ci struct device *dev; 8762306a36Sopenharmony_ci}; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic void xgene_rng_expired_timer(struct timer_list *t) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci struct xgene_rng_dev *ctx = from_timer(ctx, t, failure_timer); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci /* Clear failure counter as timer expired */ 9462306a36Sopenharmony_ci disable_irq(ctx->irq); 9562306a36Sopenharmony_ci ctx->failure_cnt = 0; 9662306a36Sopenharmony_ci del_timer(&ctx->failure_timer); 9762306a36Sopenharmony_ci enable_irq(ctx->irq); 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic void xgene_rng_start_timer(struct xgene_rng_dev *ctx) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci ctx->failure_timer.expires = jiffies + 120 * HZ; 10362306a36Sopenharmony_ci add_timer(&ctx->failure_timer); 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci/* 10762306a36Sopenharmony_ci * Initialize or reinit free running oscillators (FROs) 10862306a36Sopenharmony_ci */ 10962306a36Sopenharmony_cistatic void xgene_rng_init_fro(struct xgene_rng_dev *ctx, u32 fro_val) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci writel(fro_val, ctx->csr_base + RNG_FRODETUNE); 11262306a36Sopenharmony_ci writel(0x00000000, ctx->csr_base + RNG_ALARMMASK); 11362306a36Sopenharmony_ci writel(0x00000000, ctx->csr_base + RNG_ALARMSTOP); 11462306a36Sopenharmony_ci writel(0xFFFFFFFF, ctx->csr_base + RNG_FROENABLE); 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic void xgene_rng_chk_overflow(struct xgene_rng_dev *ctx) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci u32 val; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci val = readl(ctx->csr_base + RNG_INTR_STS_ACK); 12262306a36Sopenharmony_ci if (val & MONOBIT_FAIL_MASK) 12362306a36Sopenharmony_ci /* 12462306a36Sopenharmony_ci * LFSR detected an out-of-bounds number of 1s after 12562306a36Sopenharmony_ci * checking 20,000 bits (test T1 as specified in the 12662306a36Sopenharmony_ci * AIS-31 standard) 12762306a36Sopenharmony_ci */ 12862306a36Sopenharmony_ci dev_err(ctx->dev, "test monobit failure error 0x%08X\n", val); 12962306a36Sopenharmony_ci if (val & POKER_FAIL_MASK) 13062306a36Sopenharmony_ci /* 13162306a36Sopenharmony_ci * LFSR detected an out-of-bounds value in at least one 13262306a36Sopenharmony_ci * of the 16 poker_count_X counters or an out of bounds sum 13362306a36Sopenharmony_ci * of squares value after checking 20,000 bits (test T2 as 13462306a36Sopenharmony_ci * specified in the AIS-31 standard) 13562306a36Sopenharmony_ci */ 13662306a36Sopenharmony_ci dev_err(ctx->dev, "test poker failure error 0x%08X\n", val); 13762306a36Sopenharmony_ci if (val & LONG_RUN_FAIL_MASK) 13862306a36Sopenharmony_ci /* 13962306a36Sopenharmony_ci * LFSR detected a sequence of 34 identical bits 14062306a36Sopenharmony_ci * (test T4 as specified in the AIS-31 standard) 14162306a36Sopenharmony_ci */ 14262306a36Sopenharmony_ci dev_err(ctx->dev, "test long run failure error 0x%08X\n", val); 14362306a36Sopenharmony_ci if (val & RUN_FAIL_MASK) 14462306a36Sopenharmony_ci /* 14562306a36Sopenharmony_ci * LFSR detected an outof-bounds value for at least one 14662306a36Sopenharmony_ci * of the running counters after checking 20,000 bits 14762306a36Sopenharmony_ci * (test T3 as specified in the AIS-31 standard) 14862306a36Sopenharmony_ci */ 14962306a36Sopenharmony_ci dev_err(ctx->dev, "test run failure error 0x%08X\n", val); 15062306a36Sopenharmony_ci if (val & NOISE_FAIL_MASK) 15162306a36Sopenharmony_ci /* LFSR detected a sequence of 48 identical bits */ 15262306a36Sopenharmony_ci dev_err(ctx->dev, "noise failure error 0x%08X\n", val); 15362306a36Sopenharmony_ci if (val & STUCK_OUT_MASK) 15462306a36Sopenharmony_ci /* 15562306a36Sopenharmony_ci * Detected output data registers generated same value twice 15662306a36Sopenharmony_ci * in a row 15762306a36Sopenharmony_ci */ 15862306a36Sopenharmony_ci dev_err(ctx->dev, "stuck out failure error 0x%08X\n", val); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci if (val & SHUTDOWN_OFLO_MASK) { 16162306a36Sopenharmony_ci u32 frostopped; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci /* FROs shut down after a second error event. Try recover. */ 16462306a36Sopenharmony_ci if (++ctx->failure_cnt == 1) { 16562306a36Sopenharmony_ci /* 1st time, just recover */ 16662306a36Sopenharmony_ci ctx->failure_ts = jiffies; 16762306a36Sopenharmony_ci frostopped = readl(ctx->csr_base + RNG_ALARMSTOP); 16862306a36Sopenharmony_ci xgene_rng_init_fro(ctx, frostopped); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci /* 17162306a36Sopenharmony_ci * We must start a timer to clear out this error 17262306a36Sopenharmony_ci * in case the system timer wrap around 17362306a36Sopenharmony_ci */ 17462306a36Sopenharmony_ci xgene_rng_start_timer(ctx); 17562306a36Sopenharmony_ci } else { 17662306a36Sopenharmony_ci /* 2nd time failure in lesser than 1 minute? */ 17762306a36Sopenharmony_ci if (time_after(ctx->failure_ts + 60 * HZ, jiffies)) { 17862306a36Sopenharmony_ci dev_err(ctx->dev, 17962306a36Sopenharmony_ci "FRO shutdown failure error 0x%08X\n", 18062306a36Sopenharmony_ci val); 18162306a36Sopenharmony_ci } else { 18262306a36Sopenharmony_ci /* 2nd time failure after 1 minutes, recover */ 18362306a36Sopenharmony_ci ctx->failure_ts = jiffies; 18462306a36Sopenharmony_ci ctx->failure_cnt = 1; 18562306a36Sopenharmony_ci /* 18662306a36Sopenharmony_ci * We must start a timer to clear out this 18762306a36Sopenharmony_ci * error in case the system timer wrap 18862306a36Sopenharmony_ci * around 18962306a36Sopenharmony_ci */ 19062306a36Sopenharmony_ci xgene_rng_start_timer(ctx); 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci frostopped = readl(ctx->csr_base + RNG_ALARMSTOP); 19362306a36Sopenharmony_ci xgene_rng_init_fro(ctx, frostopped); 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci /* Clear them all */ 19762306a36Sopenharmony_ci writel(val, ctx->csr_base + RNG_INTR_STS_ACK); 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistatic irqreturn_t xgene_rng_irq_handler(int irq, void *id) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci struct xgene_rng_dev *ctx = id; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci /* RNG Alarm Counter overflow */ 20562306a36Sopenharmony_ci xgene_rng_chk_overflow(ctx); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci return IRQ_HANDLED; 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic int xgene_rng_data_present(struct hwrng *rng, int wait) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci struct xgene_rng_dev *ctx = (struct xgene_rng_dev *) rng->priv; 21362306a36Sopenharmony_ci u32 i, val = 0; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci for (i = 0; i < XGENE_RNG_RETRY_COUNT; i++) { 21662306a36Sopenharmony_ci val = readl(ctx->csr_base + RNG_INTR_STS_ACK); 21762306a36Sopenharmony_ci if ((val & READY_MASK) || !wait) 21862306a36Sopenharmony_ci break; 21962306a36Sopenharmony_ci udelay(XGENE_RNG_RETRY_INTERVAL); 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci return (val & READY_MASK); 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cistatic int xgene_rng_data_read(struct hwrng *rng, u32 *data) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci struct xgene_rng_dev *ctx = (struct xgene_rng_dev *) rng->priv; 22862306a36Sopenharmony_ci int i; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci for (i = 0; i < ctx->datum_size; i++) 23162306a36Sopenharmony_ci data[i] = readl(ctx->csr_base + RNG_INOUT_0 + i * 4); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci /* Clear ready bit to start next transaction */ 23462306a36Sopenharmony_ci writel(READY_MASK, ctx->csr_base + RNG_INTR_STS_ACK); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci return ctx->datum_size << 2; 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic void xgene_rng_init_internal(struct xgene_rng_dev *ctx) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci u32 val; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci writel(0x00000000, ctx->csr_base + RNG_CONTROL); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci val = MAX_REFILL_CYCLES_SET(0, 10); 24662306a36Sopenharmony_ci val = MIN_REFILL_CYCLES_SET(val, 10); 24762306a36Sopenharmony_ci writel(val, ctx->csr_base + RNG_CONFIG); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci val = ALARM_THRESHOLD_SET(0, 0xFF); 25062306a36Sopenharmony_ci writel(val, ctx->csr_base + RNG_ALARMCNT); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci xgene_rng_init_fro(ctx, 0); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci writel(MONOBIT_FAIL_MASK | 25562306a36Sopenharmony_ci POKER_FAIL_MASK | 25662306a36Sopenharmony_ci LONG_RUN_FAIL_MASK | 25762306a36Sopenharmony_ci RUN_FAIL_MASK | 25862306a36Sopenharmony_ci NOISE_FAIL_MASK | 25962306a36Sopenharmony_ci STUCK_OUT_MASK | 26062306a36Sopenharmony_ci SHUTDOWN_OFLO_MASK | 26162306a36Sopenharmony_ci READY_MASK, ctx->csr_base + RNG_INTR_STS_ACK); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci val = ENABLE_RNG_SET(0, 1); 26462306a36Sopenharmony_ci val = MONOBIT_FAIL_MASK_SET(val, 1); 26562306a36Sopenharmony_ci val = POKER_FAIL_MASK_SET(val, 1); 26662306a36Sopenharmony_ci val = LONG_RUN_FAIL_MASK_SET(val, 1); 26762306a36Sopenharmony_ci val = RUN_FAIL_MASK_SET(val, 1); 26862306a36Sopenharmony_ci val = NOISE_FAIL_MASK_SET(val, 1); 26962306a36Sopenharmony_ci val = STUCK_OUT_MASK_SET(val, 1); 27062306a36Sopenharmony_ci val = SHUTDOWN_OFLO_MASK_SET(val, 1); 27162306a36Sopenharmony_ci writel(val, ctx->csr_base + RNG_CONTROL); 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_cistatic int xgene_rng_init(struct hwrng *rng) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci struct xgene_rng_dev *ctx = (struct xgene_rng_dev *) rng->priv; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci ctx->failure_cnt = 0; 27962306a36Sopenharmony_ci timer_setup(&ctx->failure_timer, xgene_rng_expired_timer, 0); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci ctx->revision = readl(ctx->csr_base + RNG_EIP_REV); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci dev_dbg(ctx->dev, "Rev %d.%d.%d\n", 28462306a36Sopenharmony_ci MAJOR_HW_REV_RD(ctx->revision), 28562306a36Sopenharmony_ci MINOR_HW_REV_RD(ctx->revision), 28662306a36Sopenharmony_ci HW_PATCH_LEVEL_RD(ctx->revision)); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci dev_dbg(ctx->dev, "Options 0x%08X", 28962306a36Sopenharmony_ci readl(ctx->csr_base + RNG_OPTIONS)); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci xgene_rng_init_internal(ctx); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci ctx->datum_size = RNG_MAX_DATUM; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci return 0; 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci#ifdef CONFIG_ACPI 29962306a36Sopenharmony_cistatic const struct acpi_device_id xgene_rng_acpi_match[] = { 30062306a36Sopenharmony_ci { "APMC0D18", }, 30162306a36Sopenharmony_ci { } 30262306a36Sopenharmony_ci}; 30362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, xgene_rng_acpi_match); 30462306a36Sopenharmony_ci#endif 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_cistatic struct hwrng xgene_rng_func = { 30762306a36Sopenharmony_ci .name = "xgene-rng", 30862306a36Sopenharmony_ci .init = xgene_rng_init, 30962306a36Sopenharmony_ci .data_present = xgene_rng_data_present, 31062306a36Sopenharmony_ci .data_read = xgene_rng_data_read, 31162306a36Sopenharmony_ci}; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cistatic int xgene_rng_probe(struct platform_device *pdev) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci struct xgene_rng_dev *ctx; 31662306a36Sopenharmony_ci struct clk *clk; 31762306a36Sopenharmony_ci int rc = 0; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); 32062306a36Sopenharmony_ci if (!ctx) 32162306a36Sopenharmony_ci return -ENOMEM; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci ctx->dev = &pdev->dev; 32462306a36Sopenharmony_ci platform_set_drvdata(pdev, ctx); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci ctx->csr_base = devm_platform_ioremap_resource(pdev, 0); 32762306a36Sopenharmony_ci if (IS_ERR(ctx->csr_base)) 32862306a36Sopenharmony_ci return PTR_ERR(ctx->csr_base); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci rc = platform_get_irq(pdev, 0); 33162306a36Sopenharmony_ci if (rc < 0) 33262306a36Sopenharmony_ci return rc; 33362306a36Sopenharmony_ci ctx->irq = rc; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci dev_dbg(&pdev->dev, "APM X-Gene RNG BASE %p ALARM IRQ %d", 33662306a36Sopenharmony_ci ctx->csr_base, ctx->irq); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci rc = devm_request_irq(&pdev->dev, ctx->irq, xgene_rng_irq_handler, 0, 33962306a36Sopenharmony_ci dev_name(&pdev->dev), ctx); 34062306a36Sopenharmony_ci if (rc) 34162306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, rc, "Could not request RNG alarm IRQ\n"); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci /* Enable IP clock */ 34462306a36Sopenharmony_ci clk = devm_clk_get_optional_enabled(&pdev->dev, NULL); 34562306a36Sopenharmony_ci if (IS_ERR(clk)) 34662306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, PTR_ERR(clk), "Couldn't get the clock for RNG\n"); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci xgene_rng_func.priv = (unsigned long) ctx; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci rc = devm_hwrng_register(&pdev->dev, &xgene_rng_func); 35162306a36Sopenharmony_ci if (rc) 35262306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, rc, "RNG registering failed\n"); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci rc = device_init_wakeup(&pdev->dev, 1); 35562306a36Sopenharmony_ci if (rc) 35662306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, rc, "RNG device_init_wakeup failed\n"); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci return 0; 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_cistatic int xgene_rng_remove(struct platform_device *pdev) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci int rc; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci rc = device_init_wakeup(&pdev->dev, 0); 36662306a36Sopenharmony_ci if (rc) 36762306a36Sopenharmony_ci dev_err(&pdev->dev, "RNG init wakeup failed error %d\n", rc); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci return 0; 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cistatic const struct of_device_id xgene_rng_of_match[] = { 37362306a36Sopenharmony_ci { .compatible = "apm,xgene-rng" }, 37462306a36Sopenharmony_ci { } 37562306a36Sopenharmony_ci}; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, xgene_rng_of_match); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_cistatic struct platform_driver xgene_rng_driver = { 38062306a36Sopenharmony_ci .probe = xgene_rng_probe, 38162306a36Sopenharmony_ci .remove = xgene_rng_remove, 38262306a36Sopenharmony_ci .driver = { 38362306a36Sopenharmony_ci .name = "xgene-rng", 38462306a36Sopenharmony_ci .of_match_table = xgene_rng_of_match, 38562306a36Sopenharmony_ci .acpi_match_table = ACPI_PTR(xgene_rng_acpi_match), 38662306a36Sopenharmony_ci }, 38762306a36Sopenharmony_ci}; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_cimodule_platform_driver(xgene_rng_driver); 39062306a36Sopenharmony_ciMODULE_DESCRIPTION("APM X-Gene RNG driver"); 39162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 392