Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (c) 2022 Nuvoton Technology Corp. */ #include <dm.h> #include <malloc.h> #include <rng.h> #include <uboot_aes.h> #include <asm/io.h> #define RNGCS_RNGE BIT(0) #define RNGCS_DVALID BIT(1) #define RNGCS_CLKP(range) ((0x0f & (range)) << 2) #define RNGMODE_M1ROSEL_VAL (0x02) /* Ring Oscillator Select for Method I */ enum { RNG_CLKP_80_100_MHZ = 0x00, /*default */ RNG_CLKP_60_80_MHZ = 0x01, RNG_CLKP_50_60_MHZ = 0x02, RNG_CLKP_40_50_MHZ = 0x03, RNG_CLKP_30_40_MHZ = 0x04, RNG_CLKP_25_30_MHZ = 0x05, RNG_CLKP_20_25_MHZ = 0x06, RNG_CLKP_5_20_MHZ = 0x07, RNG_CLKP_2_15_MHZ = 0x08, RNG_CLKP_9_12_MHZ = 0x09, RNG_CLKP_7_9_MHZ = 0x0A, RNG_CLKP_6_7_MHZ = 0x0B, RNG_CLKP_5_6_MHZ = 0x0C, RNG_CLKP_4_5_MHZ = 0x0D, RNG_CLKP_3_4_MHZ = 0x0E, RNG_NUM_OF_CLKP }; struct npcm_rng_regs { unsigned int rngcs; unsigned int rngd; unsigned int rngmode; }; struct npcm_rng_priv { struct npcm_rng_regs *regs; }; static struct npcm_rng_priv *rng_priv; void npcm_rng_init(void) { struct npcm_rng_regs *regs = rng_priv->regs; int init; /* check if rng enabled */ init = readb(®s->rngcs); if ((init & RNGCS_RNGE) == 0) { /* init rng */ writeb(RNGCS_CLKP(RNG_CLKP_20_25_MHZ) | RNGCS_RNGE, ®s->rngcs); writeb(RNGMODE_M1ROSEL_VAL, ®s->rngmode); } } void npcm_rng_disable(void) { struct npcm_rng_regs *regs = rng_priv->regs; /* disable rng */ writeb(0, ®s->rngcs); writeb(0, ®s->rngmode); } void srand(unsigned int seed) { /* no need to seed for now */ } int npcm_rng_read(struct udevice *dev, void *data, size_t max) { struct npcm_rng_regs *regs = rng_priv->regs; int i; int ret_val = 0; char *buf = data; npcm_rng_init(); printf("NPCM HW RNG\n"); /* Wait for RNG done (max bytes) */ for (i = 0; i < max; i++) { /* wait until DVALID is set */ while ((readb(®s->rngcs) & RNGCS_DVALID) == 0) ; buf[i] = ((unsigned int)readb(®s->rngd) & 0x000000FF); } return ret_val; } unsigned int rand_r(unsigned int *seedp) { struct npcm_rng_regs *regs = rng_priv->regs; int i; unsigned int ret_val = 0; npcm_rng_init(); /* Wait for RNG done (4 bytes) */ for (i = 0; i < 4 ; i++) { /* wait until DVALID is set */ while ((readb(®s->rngcs) & RNGCS_DVALID) == 0) ; ret_val |= (((unsigned int)readb(®s->rngd) & 0x000000FF) << (i * 8)); } return ret_val; } unsigned int rand(void) { return rand_r(NULL); } static int npcm_rng_bind(struct udevice *dev) { rng_priv = calloc(1, sizeof(struct npcm_rng_priv)); if (!rng_priv) return -ENOMEM; rng_priv->regs = dev_remap_addr_index(dev, 0); if (!rng_priv->regs) { printf("Cannot find rng reg address, binding failed\n"); return -EINVAL; } printf("RNG: NPCM RNG module bind OK\n"); return 0; } static const struct udevice_id npcm_rng_ids[] = { { .compatible = "nuvoton,npcm845-rng" }, { .compatible = "nuvoton,npcm750-rng" }, { } }; static const struct dm_rng_ops npcm_rng_ops = { .read = npcm_rng_read, }; U_BOOT_DRIVER(npcm_rng) = { .name = "npcm_rng", .id = UCLASS_RNG, .ops = &npcm_rng_ops, .of_match = npcm_rng_ids, .priv_auto = sizeof(struct npcm_rng_priv), .bind = npcm_rng_bind, }; |