1de266e27SJorge Ramirez-Ortiz // SPDX-License-Identifier: BSD-2-Clause 2de266e27SJorge Ramirez-Ortiz /* 3de266e27SJorge Ramirez-Ortiz * (c) 2021 Jorge Ramirez <jorge@foundries.io>, Foundries Ltd. 4de266e27SJorge Ramirez-Ortiz */ 5de266e27SJorge Ramirez-Ortiz 6de266e27SJorge Ramirez-Ortiz #include <arm.h> 7de266e27SJorge Ramirez-Ortiz #include <crypto/crypto.h> 8de266e27SJorge Ramirez-Ortiz #include <initcall.h> 9de266e27SJorge Ramirez-Ortiz #include <io.h> 10de266e27SJorge Ramirez-Ortiz #include <kernel/boot.h> 11de266e27SJorge Ramirez-Ortiz #include <kernel/delay.h> 12de266e27SJorge Ramirez-Ortiz #include <kernel/dt.h> 13de266e27SJorge Ramirez-Ortiz #include <kernel/panic.h> 14de266e27SJorge Ramirez-Ortiz #include <libfdt.h> 15de266e27SJorge Ramirez-Ortiz #include <mm/core_memprot.h> 16de266e27SJorge Ramirez-Ortiz #include <mm/core_mmu.h> 17de266e27SJorge Ramirez-Ortiz #include <platform_config.h> 18de266e27SJorge Ramirez-Ortiz #include <rng_support.h> 19de266e27SJorge Ramirez-Ortiz #include <stdlib.h> 20de266e27SJorge Ramirez-Ortiz #include <string.h> 21de266e27SJorge Ramirez-Ortiz #include <tee/tee_cryp_utl.h> 22de266e27SJorge Ramirez-Ortiz #include <trace.h> 23de266e27SJorge Ramirez-Ortiz #include <util.h> 24de266e27SJorge Ramirez-Ortiz 25de266e27SJorge Ramirez-Ortiz #define RNG_VER 0x00 26de266e27SJorge Ramirez-Ortiz #define RNG_CMD 0x04 27de266e27SJorge Ramirez-Ortiz #define RNG_CR 0x08 28de266e27SJorge Ramirez-Ortiz #define RNG_SR 0x0C 29de266e27SJorge Ramirez-Ortiz #define RNG_ESR 0x10 30de266e27SJorge Ramirez-Ortiz #define RNG_OUT 0x14 31de266e27SJorge Ramirez-Ortiz 32de266e27SJorge Ramirez-Ortiz #define RNG_CMD_CLR_INT BIT(4) 33de266e27SJorge Ramirez-Ortiz #define RNG_CMD_CLR_ERR BIT(5) 34de266e27SJorge Ramirez-Ortiz 35de266e27SJorge Ramirez-Ortiz #define RNG_CR_AR BIT(4) 36de266e27SJorge Ramirez-Ortiz #define RNG_CR_MASK_DONE BIT(5) 37de266e27SJorge Ramirez-Ortiz #define RNG_CR_MASK_ERROR BIT(6) 38de266e27SJorge Ramirez-Ortiz 39de266e27SJorge Ramirez-Ortiz #define RNG_SR_ST_DONE BIT(4) 40de266e27SJorge Ramirez-Ortiz #define RNG_SR_SEED_DONE BIT(5) 41de266e27SJorge Ramirez-Ortiz #define RNG_SR_ERROR BIT(16) 42de266e27SJorge Ramirez-Ortiz #define RNG_SR_FIFO_LEVEL_SHIFT 8 43de266e27SJorge Ramirez-Ortiz #define RNG_SR_FIFO_LEVEL_MASK GENMASK_32(11, RNG_SR_FIFO_LEVEL_SHIFT) 44de266e27SJorge Ramirez-Ortiz 45de266e27SJorge Ramirez-Ortiz #define RNG_VER_TYPE_SHIFT 28 46de266e27SJorge Ramirez-Ortiz #define RNG_VER_TYPE_MASK GENMASK_32(31, RNG_VER_TYPE_SHIFT) 47de266e27SJorge Ramirez-Ortiz 48de266e27SJorge Ramirez-Ortiz #define RNG_ESR_STATUS_STAT_ERR BIT(3) 49de266e27SJorge Ramirez-Ortiz 50de266e27SJorge Ramirez-Ortiz #define RNG_TYPE_RNGA 0 51de266e27SJorge Ramirez-Ortiz #define RNG_TYPE_RNGB 1 52de266e27SJorge Ramirez-Ortiz #define RNG_TYPE_RNGC 2 53de266e27SJorge Ramirez-Ortiz 54de266e27SJorge Ramirez-Ortiz #define SEED_TIMEOUT 2000000 55de266e27SJorge Ramirez-Ortiz #define IRQ_TIMEOUT 1000000 56de266e27SJorge Ramirez-Ortiz 57de266e27SJorge Ramirez-Ortiz #define WORDS_IN_FIFO(__rng_sr) \ 58de266e27SJorge Ramirez-Ortiz (((__rng_sr) & RNG_SR_FIFO_LEVEL_MASK) >> RNG_SR_FIFO_LEVEL_SHIFT) 59de266e27SJorge Ramirez-Ortiz 60de266e27SJorge Ramirez-Ortiz #define RNG_TYPE(__rng_vr) \ 61de266e27SJorge Ramirez-Ortiz (((__rng_vr) & RNG_VER_TYPE_MASK) >> RNG_VER_TYPE_SHIFT) 62de266e27SJorge Ramirez-Ortiz 63de266e27SJorge Ramirez-Ortiz static struct imx_rng { 64de266e27SJorge Ramirez-Ortiz struct io_pa_va base; 65de266e27SJorge Ramirez-Ortiz size_t size; 66de266e27SJorge Ramirez-Ortiz bool ready; 67de266e27SJorge Ramirez-Ortiz uint32_t error; 68de266e27SJorge Ramirez-Ortiz } rngb = { 69de266e27SJorge Ramirez-Ortiz .base.pa = RNGB_BASE, 70de266e27SJorge Ramirez-Ortiz .size = 0x4000, 71de266e27SJorge Ramirez-Ortiz }; 72de266e27SJorge Ramirez-Ortiz 73de266e27SJorge Ramirez-Ortiz static void wait_for_irq(struct imx_rng *rng) 74de266e27SJorge Ramirez-Ortiz { 75de266e27SJorge Ramirez-Ortiz uint64_t tref = timeout_init_us(IRQ_TIMEOUT); 76de266e27SJorge Ramirez-Ortiz uint32_t status = 0; 77de266e27SJorge Ramirez-Ortiz 78de266e27SJorge Ramirez-Ortiz do { 79de266e27SJorge Ramirez-Ortiz rng->error = io_read32(rng->base.va + RNG_ESR); 80de266e27SJorge Ramirez-Ortiz status = io_read32(rng->base.va + RNG_SR); 81de266e27SJorge Ramirez-Ortiz 82de266e27SJorge Ramirez-Ortiz if (timeout_elapsed(tref)) 83de266e27SJorge Ramirez-Ortiz panic(); 84de266e27SJorge Ramirez-Ortiz 85de266e27SJorge Ramirez-Ortiz } while ((status & (RNG_SR_SEED_DONE | RNG_SR_ST_DONE)) == 0); 86de266e27SJorge Ramirez-Ortiz } 87de266e27SJorge Ramirez-Ortiz 88de266e27SJorge Ramirez-Ortiz static void irq_clear(struct imx_rng *rng) 89de266e27SJorge Ramirez-Ortiz { 90de266e27SJorge Ramirez-Ortiz io_setbits32(rng->base.va + RNG_CR, 91de266e27SJorge Ramirez-Ortiz RNG_CR_MASK_DONE | RNG_CR_MASK_ERROR); 92de266e27SJorge Ramirez-Ortiz io_setbits32(rng->base.va + RNG_CMD, 93de266e27SJorge Ramirez-Ortiz RNG_CMD_CLR_INT | RNG_CMD_CLR_ERR); 94de266e27SJorge Ramirez-Ortiz } 95de266e27SJorge Ramirez-Ortiz 96de266e27SJorge Ramirez-Ortiz static void irq_unmask(struct imx_rng *rng) 97de266e27SJorge Ramirez-Ortiz { 98de266e27SJorge Ramirez-Ortiz io_clrbits32(rng->base.va + RNG_CR, 99de266e27SJorge Ramirez-Ortiz RNG_CR_MASK_DONE | RNG_CR_MASK_ERROR); 100de266e27SJorge Ramirez-Ortiz } 101de266e27SJorge Ramirez-Ortiz 102de266e27SJorge Ramirez-Ortiz static void rng_seed(struct imx_rng *rng) 103de266e27SJorge Ramirez-Ortiz { 104de266e27SJorge Ramirez-Ortiz uint64_t tref = timeout_init_us(SEED_TIMEOUT); 105de266e27SJorge Ramirez-Ortiz 106de266e27SJorge Ramirez-Ortiz irq_clear(rng); 107de266e27SJorge Ramirez-Ortiz do { 108de266e27SJorge Ramirez-Ortiz irq_unmask(rng); 109de266e27SJorge Ramirez-Ortiz /* configure continuous auto-reseed */ 110de266e27SJorge Ramirez-Ortiz io_setbits32(rng->base.va + RNG_CR, RNG_CR_AR); 111de266e27SJorge Ramirez-Ortiz wait_for_irq(rng); 112de266e27SJorge Ramirez-Ortiz irq_clear(rng); 113de266e27SJorge Ramirez-Ortiz 114de266e27SJorge Ramirez-Ortiz if (timeout_elapsed(tref)) 115de266e27SJorge Ramirez-Ortiz panic(); 116de266e27SJorge Ramirez-Ortiz } while (rng->error); 117de266e27SJorge Ramirez-Ortiz } 118de266e27SJorge Ramirez-Ortiz 119de266e27SJorge Ramirez-Ortiz static TEE_Result map_controller_static(void) 120de266e27SJorge Ramirez-Ortiz { 121bc9618c0SAnton Rybakov rngb.base.va = (vaddr_t)core_mmu_add_mapping(MEM_AREA_IO_SEC, 122bc9618c0SAnton Rybakov rngb.base.pa, rngb.size); 123bc9618c0SAnton Rybakov if (!rngb.base.va) 124de266e27SJorge Ramirez-Ortiz return TEE_ERROR_GENERIC; 125de266e27SJorge Ramirez-Ortiz 126de266e27SJorge Ramirez-Ortiz return TEE_SUCCESS; 127de266e27SJorge Ramirez-Ortiz } 128de266e27SJorge Ramirez-Ortiz 129de266e27SJorge Ramirez-Ortiz #if !defined(CFG_DT) 130de266e27SJorge Ramirez-Ortiz static TEE_Result map_controller(void) 131de266e27SJorge Ramirez-Ortiz { 132de266e27SJorge Ramirez-Ortiz return map_controller_static(); 133de266e27SJorge Ramirez-Ortiz } 134de266e27SJorge Ramirez-Ortiz #else 135de266e27SJorge Ramirez-Ortiz static const char *const rng_match_table[] = { 136de266e27SJorge Ramirez-Ortiz "fsl,imx25-rngb", 137de266e27SJorge Ramirez-Ortiz }; 138de266e27SJorge Ramirez-Ortiz 139de266e27SJorge Ramirez-Ortiz static TEE_Result map_controller(void) 140de266e27SJorge Ramirez-Ortiz { 141de266e27SJorge Ramirez-Ortiz void *fdt = get_dt(); 142de266e27SJorge Ramirez-Ortiz unsigned int i = 0; 143de266e27SJorge Ramirez-Ortiz int off = -1; 144de266e27SJorge Ramirez-Ortiz 145de266e27SJorge Ramirez-Ortiz if (!fdt) 146de266e27SJorge Ramirez-Ortiz return map_controller_static(); 147de266e27SJorge Ramirez-Ortiz 148de266e27SJorge Ramirez-Ortiz for (i = 0; i < ARRAY_SIZE(rng_match_table); i++) { 149de266e27SJorge Ramirez-Ortiz off = fdt_node_offset_by_compatible(fdt, 0, rng_match_table[i]); 150de266e27SJorge Ramirez-Ortiz if (off >= 0) 151de266e27SJorge Ramirez-Ortiz break; 152de266e27SJorge Ramirez-Ortiz } 153de266e27SJorge Ramirez-Ortiz 154de266e27SJorge Ramirez-Ortiz if (off < 0) 155de266e27SJorge Ramirez-Ortiz return map_controller_static(); 156de266e27SJorge Ramirez-Ortiz 157de266e27SJorge Ramirez-Ortiz if (dt_enable_secure_status(fdt, off)) 158de266e27SJorge Ramirez-Ortiz return TEE_ERROR_NOT_SUPPORTED; 159de266e27SJorge Ramirez-Ortiz 160*a5d5bbc8SVesa Jääskeläinen if (dt_map_dev(fdt, off, &rngb.base.va, &rngb.size, DT_MAP_AUTO) < 0) 161de266e27SJorge Ramirez-Ortiz return TEE_ERROR_NOT_SUPPORTED; 162de266e27SJorge Ramirez-Ortiz 163de266e27SJorge Ramirez-Ortiz rngb.base.pa = virt_to_phys((void *)rngb.base.va); 164de266e27SJorge Ramirez-Ortiz 165de266e27SJorge Ramirez-Ortiz return TEE_SUCCESS; 166de266e27SJorge Ramirez-Ortiz } 167de266e27SJorge Ramirez-Ortiz #endif 168de266e27SJorge Ramirez-Ortiz 169f6406a3cSAndrew Davis TEE_Result hw_get_random_bytes(void *buf, size_t len) 170de266e27SJorge Ramirez-Ortiz { 171de266e27SJorge Ramirez-Ortiz uint32_t *rngbuf = buf; 172de266e27SJorge Ramirez-Ortiz uint32_t status = 0; 173de266e27SJorge Ramirez-Ortiz uint32_t val = 0; 174de266e27SJorge Ramirez-Ortiz 175de266e27SJorge Ramirez-Ortiz if (!rngb.ready) 176de266e27SJorge Ramirez-Ortiz return TEE_ERROR_BAD_STATE; 177de266e27SJorge Ramirez-Ortiz 178de266e27SJorge Ramirez-Ortiz while (len) { 179de266e27SJorge Ramirez-Ortiz status = io_read32(rngb.base.va + RNG_SR); 180de266e27SJorge Ramirez-Ortiz if (status & RNG_SR_ERROR) 181de266e27SJorge Ramirez-Ortiz return TEE_ERROR_BAD_STATE; 182de266e27SJorge Ramirez-Ortiz 183de266e27SJorge Ramirez-Ortiz if (WORDS_IN_FIFO(status)) { 184de266e27SJorge Ramirez-Ortiz val = io_read32(rngb.base.va + RNG_OUT); 185de266e27SJorge Ramirez-Ortiz if (len > sizeof(uint32_t)) { 186de266e27SJorge Ramirez-Ortiz len = len - sizeof(uint32_t); 187de266e27SJorge Ramirez-Ortiz memcpy(rngbuf, &val, sizeof(uint32_t)); 188de266e27SJorge Ramirez-Ortiz rngbuf++; 189de266e27SJorge Ramirez-Ortiz } else { 190de266e27SJorge Ramirez-Ortiz memcpy(rngbuf, &val, len); 191de266e27SJorge Ramirez-Ortiz len = 0; 192de266e27SJorge Ramirez-Ortiz } 193de266e27SJorge Ramirez-Ortiz } 194de266e27SJorge Ramirez-Ortiz } 195de266e27SJorge Ramirez-Ortiz 196de266e27SJorge Ramirez-Ortiz return TEE_SUCCESS; 197de266e27SJorge Ramirez-Ortiz } 198de266e27SJorge Ramirez-Ortiz 199de266e27SJorge Ramirez-Ortiz void plat_rng_init(void) 200de266e27SJorge Ramirez-Ortiz { 201de266e27SJorge Ramirez-Ortiz } 202de266e27SJorge Ramirez-Ortiz 203de266e27SJorge Ramirez-Ortiz static TEE_Result rngb_init(void) 204de266e27SJorge Ramirez-Ortiz { 205de266e27SJorge Ramirez-Ortiz uint32_t type = 0; 206de266e27SJorge Ramirez-Ortiz 207de266e27SJorge Ramirez-Ortiz if (map_controller()) 208de266e27SJorge Ramirez-Ortiz panic(); 209de266e27SJorge Ramirez-Ortiz 210de266e27SJorge Ramirez-Ortiz type = RNG_TYPE(io_read32(rngb.base.va + RNG_VER)); 211de266e27SJorge Ramirez-Ortiz if (type != RNG_TYPE_RNGB && type != RNG_TYPE_RNGC) 212de266e27SJorge Ramirez-Ortiz panic(); 213de266e27SJorge Ramirez-Ortiz 214de266e27SJorge Ramirez-Ortiz rng_seed(&rngb); 215de266e27SJorge Ramirez-Ortiz rngb.ready = true; 216de266e27SJorge Ramirez-Ortiz 217de266e27SJorge Ramirez-Ortiz return TEE_SUCCESS; 218de266e27SJorge Ramirez-Ortiz } 219de266e27SJorge Ramirez-Ortiz 220de266e27SJorge Ramirez-Ortiz driver_init(rngb_init); 221