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