1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2020 Fuzhou Rockchip Electronics Co., Ltd 4 */ 5 #include <asm/arch-rockchip/hardware.h> 6 #include <asm/io.h> 7 #include <common.h> 8 #include <dm.h> 9 #include <linux/iopoll.h> 10 #include <linux/string.h> 11 #include <rng.h> 12 13 #define RK_HW_RNG_MAX 32 14 15 #define _SBF(s, v) ((v) << (s)) 16 17 /* start of CRYPTO V1 register define */ 18 #define CRYPTO_V1_CTRL 0x0008 19 #define CRYPTO_V1_RNG_START BIT(8) 20 #define CRYPTO_V1_RNG_FLUSH BIT(9) 21 22 #define CRYPTO_V1_TRNG_CTRL 0x0200 23 #define CRYPTO_V1_OSC_ENABLE BIT(16) 24 #define CRYPTO_V1_TRNG_SAMPLE_PERIOD(x) (x) 25 26 #define CRYPTO_V1_TRNG_DOUT_0 0x0204 27 /* end of CRYPTO V1 register define */ 28 29 /* start of CRYPTO V2 register define */ 30 #define CRYPTO_V2_RNG_CTL 0x0400 31 #define CRYPTO_V2_RNG_64_BIT_LEN _SBF(4, 0x00) 32 #define CRYPTO_V2_RNG_128_BIT_LEN _SBF(4, 0x01) 33 #define CRYPTO_V2_RNG_192_BIT_LEN _SBF(4, 0x02) 34 #define CRYPTO_V2_RNG_256_BIT_LEN _SBF(4, 0x03) 35 #define CRYPTO_V2_RNG_FATESY_SOC_RING _SBF(2, 0x00) 36 #define CRYPTO_V2_RNG_SLOWER_SOC_RING_0 _SBF(2, 0x01) 37 #define CRYPTO_V2_RNG_SLOWER_SOC_RING_1 _SBF(2, 0x02) 38 #define CRYPTO_V2_RNG_SLOWEST_SOC_RING _SBF(2, 0x03) 39 #define CRYPTO_V2_RNG_ENABLE BIT(1) 40 #define CRYPTO_V2_RNG_START BIT(0) 41 #define CRYPTO_V2_RNG_SAMPLE_CNT 0x0404 42 #define CRYPTO_V2_RNG_DOUT_0 0x0410 43 /* end of CRYPTO V2 register define */ 44 45 #define RK_RNG_TIME_OUT 50000 /* max 50ms */ 46 47 struct rk_rng_soc_data { 48 int (*rk_rng_read)(struct udevice *dev, void *data, size_t len); 49 }; 50 51 struct rk_rng_platdata { 52 fdt_addr_t base; 53 struct rk_rng_soc_data *soc_data; 54 }; 55 56 static int rk_rng_read_regs(fdt_addr_t addr, void *buf, size_t size) 57 { 58 u32 count = RK_HW_RNG_MAX / sizeof(u32); 59 u32 reg, tmp_len; 60 61 if (size > RK_HW_RNG_MAX) 62 return -EINVAL; 63 64 while (size && count) { 65 reg = readl(addr); 66 tmp_len = min(size, sizeof(u32)); 67 memcpy(buf, ®, tmp_len); 68 addr += sizeof(u32); 69 buf += tmp_len; 70 size -= tmp_len; 71 count--; 72 } 73 74 return 0; 75 } 76 77 static int rk_v1_rng_read(struct udevice *dev, void *data, size_t len) 78 { 79 struct rk_rng_platdata *pdata = dev_get_priv(dev); 80 u32 reg = 0; 81 int retval; 82 83 if (len > RK_HW_RNG_MAX) 84 return -EINVAL; 85 86 /* enable osc_ring to get entropy, sample period is set as 100 */ 87 writel(CRYPTO_V1_OSC_ENABLE | CRYPTO_V1_TRNG_SAMPLE_PERIOD(100), 88 pdata->base + CRYPTO_V1_TRNG_CTRL); 89 90 rk_clrsetreg(pdata->base + CRYPTO_V1_CTRL, CRYPTO_V1_RNG_START, 91 CRYPTO_V1_RNG_START); 92 93 retval = readl_poll_timeout(pdata->base + CRYPTO_V1_CTRL, reg, 94 !(reg & CRYPTO_V1_RNG_START), 95 RK_RNG_TIME_OUT); 96 if (retval) 97 goto exit; 98 99 rk_rng_read_regs(pdata->base + CRYPTO_V1_TRNG_DOUT_0, data, len); 100 101 exit: 102 /* close TRNG */ 103 rk_clrreg(pdata->base + CRYPTO_V1_CTRL, CRYPTO_V1_RNG_START); 104 105 return 0; 106 } 107 108 static int rk_v2_rng_read(struct udevice *dev, void *data, size_t len) 109 { 110 struct rk_rng_platdata *pdata = dev_get_priv(dev); 111 u32 reg = 0; 112 int retval; 113 114 if (len > RK_HW_RNG_MAX) 115 return -EINVAL; 116 117 /* enable osc_ring to get entropy, sample period is set as 100 */ 118 writel(100, pdata->base + CRYPTO_V2_RNG_SAMPLE_CNT); 119 120 reg |= CRYPTO_V2_RNG_256_BIT_LEN; 121 reg |= CRYPTO_V2_RNG_SLOWER_SOC_RING_0; 122 reg |= CRYPTO_V2_RNG_ENABLE; 123 reg |= CRYPTO_V2_RNG_START; 124 125 rk_clrsetreg(pdata->base + CRYPTO_V2_RNG_CTL, 0xffff, reg); 126 127 retval = readl_poll_timeout(pdata->base + CRYPTO_V2_RNG_CTL, reg, 128 !(reg & CRYPTO_V2_RNG_START), 129 RK_RNG_TIME_OUT); 130 if (retval) 131 goto exit; 132 133 rk_rng_read_regs(pdata->base + CRYPTO_V2_RNG_DOUT_0, data, len); 134 135 exit: 136 /* close TRNG */ 137 rk_clrreg(pdata->base + CRYPTO_V2_RNG_CTL, 0xffff); 138 139 return retval; 140 } 141 142 static int rockchip_rng_read(struct udevice *dev, void *data, size_t len) 143 { 144 unsigned char *buf = data; 145 unsigned int i; 146 int ret = -EIO; 147 148 struct rk_rng_platdata *pdata = dev_get_priv(dev); 149 150 if (!len) 151 return 0; 152 153 if (!pdata->soc_data || !pdata->soc_data->rk_rng_read) 154 return -EINVAL; 155 156 for (i = 0; i < len / RK_HW_RNG_MAX; i++, buf += RK_HW_RNG_MAX) { 157 ret = pdata->soc_data->rk_rng_read(dev, buf, RK_HW_RNG_MAX); 158 if (ret) 159 goto exit; 160 } 161 162 if (len % RK_HW_RNG_MAX) 163 ret = pdata->soc_data->rk_rng_read(dev, buf, 164 len % RK_HW_RNG_MAX); 165 166 exit: 167 return ret; 168 } 169 170 static int rockchip_rng_ofdata_to_platdata(struct udevice *dev) 171 { 172 struct rk_rng_platdata *pdata = dev_get_priv(dev); 173 174 memset(pdata, 0x00, sizeof(*pdata)); 175 176 pdata->base = (fdt_addr_t)dev_read_addr_ptr(dev); 177 if (!pdata->base) 178 return -ENOMEM; 179 180 return 0; 181 } 182 183 static int rockchip_rng_probe(struct udevice *dev) 184 { 185 struct rk_rng_platdata *pdata = dev_get_priv(dev); 186 187 pdata->soc_data = (struct rk_rng_soc_data *)dev_get_driver_data(dev); 188 189 return 0; 190 } 191 192 static const struct rk_rng_soc_data rk_rng_v1_soc_data = { 193 .rk_rng_read = rk_v1_rng_read, 194 }; 195 196 static const struct rk_rng_soc_data rk_rng_v2_soc_data = { 197 .rk_rng_read = rk_v2_rng_read, 198 }; 199 200 static const struct dm_rng_ops rockchip_rng_ops = { 201 .read = rockchip_rng_read, 202 }; 203 204 static const struct udevice_id rockchip_rng_match[] = { 205 { 206 .compatible = "rockchip,cryptov1-rng", 207 .data = (ulong)&rk_rng_v1_soc_data, 208 }, 209 { 210 .compatible = "rockchip,cryptov2-rng", 211 .data = (ulong)&rk_rng_v2_soc_data, 212 }, 213 {}, 214 }; 215 216 U_BOOT_DRIVER(rockchip_rng) = { 217 .name = "rockchip-rng", 218 .id = UCLASS_RNG, 219 .of_match = rockchip_rng_match, 220 .ops = &rockchip_rng_ops, 221 .probe = rockchip_rng_probe, 222 .ofdata_to_platdata = rockchip_rng_ofdata_to_platdata, 223 .priv_auto_alloc_size = sizeof(struct rk_rng_platdata), 224 }; 225