xref: /optee_os/core/drivers/dra7_rng.c (revision 1bb929836182ecb96d2d9d268daa807c67596396)
1*1bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
24d168941SAndrew F. Davis /*
34d168941SAndrew F. Davis  * Copyright (c) 2016, Linaro Limited
44d168941SAndrew F. Davis  * All rights reserved.
54d168941SAndrew F. Davis  *
64d168941SAndrew F. Davis  * Redistribution and use in source and binary forms, with or without
74d168941SAndrew F. Davis  * modification, are permitted provided that the following conditions are met:
84d168941SAndrew F. Davis  *
94d168941SAndrew F. Davis  * 1. Redistributions of source code must retain the above copyright notice,
104d168941SAndrew F. Davis  * this list of conditions and the following disclaimer.
114d168941SAndrew F. Davis  *
124d168941SAndrew F. Davis  * 2. Redistributions in binary form must reproduce the above copyright notice,
134d168941SAndrew F. Davis  * this list of conditions and the following disclaimer in the documentation
144d168941SAndrew F. Davis  * and/or other materials provided with the distribution.
154d168941SAndrew F. Davis  *
164d168941SAndrew F. Davis  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
174d168941SAndrew F. Davis  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
184d168941SAndrew F. Davis  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
194d168941SAndrew F. Davis  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
204d168941SAndrew F. Davis  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
214d168941SAndrew F. Davis  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
224d168941SAndrew F. Davis  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
234d168941SAndrew F. Davis  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
244d168941SAndrew F. Davis  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
254d168941SAndrew F. Davis  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
264d168941SAndrew F. Davis  * POSSIBILITY OF SUCH DAMAGE.
274d168941SAndrew F. Davis  */
284d168941SAndrew F. Davis 
294d168941SAndrew F. Davis #include <initcall.h>
304d168941SAndrew F. Davis #include <io.h>
314d168941SAndrew F. Davis #include <keep.h>
324d168941SAndrew F. Davis #include <kernel/interrupt.h>
334d168941SAndrew F. Davis #include <kernel/misc.h>
344d168941SAndrew F. Davis #include <kernel/spinlock.h>
354d168941SAndrew F. Davis #include <mm/core_memprot.h>
364d168941SAndrew F. Davis #include <mm/core_mmu.h>
374d168941SAndrew F. Davis #include <platform_config.h>
384d168941SAndrew F. Davis #include <rng_support.h>
394d168941SAndrew F. Davis 
404d168941SAndrew F. Davis #define	RNG_OUTPUT_L            0x0000
414d168941SAndrew F. Davis #define	RNG_OUTPUT_H            0x0004
424d168941SAndrew F. Davis #define	RNG_STATUS              0x0008
434d168941SAndrew F. Davis #  define RNG_READY             BIT(0)
444d168941SAndrew F. Davis #  define SHUTDOWN_OFLO         BIT(1)
454d168941SAndrew F. Davis #define	RNG_INTMASK             0x000C
464d168941SAndrew F. Davis #define	RNG_INTACK              0x0010
474d168941SAndrew F. Davis #define	RNG_CONTROL             0x0014
484d168941SAndrew F. Davis #  define ENABLE_TRNG           BIT(10)
494d168941SAndrew F. Davis #define	RNG_CONFIG              0x0018
504d168941SAndrew F. Davis #define	RNG_ALARMCNT            0x001C
514d168941SAndrew F. Davis #define	RNG_FROENABLE           0x0020
524d168941SAndrew F. Davis #define	RNG_FRODETUNE           0x0024
534d168941SAndrew F. Davis #define	RNG_ALARMMASK           0x0028
544d168941SAndrew F. Davis #define	RNG_ALARMSTOP           0x002C
554d168941SAndrew F. Davis #define	RNG_LFSR_L              0x0030
564d168941SAndrew F. Davis #define	RNG_LFSR_M              0x0034
574d168941SAndrew F. Davis #define	RNG_LFSR_H              0x0038
584d168941SAndrew F. Davis #define	RNG_COUNT               0x003C
594d168941SAndrew F. Davis #define	RNG_OPTIONS             0x0078
604d168941SAndrew F. Davis #define	RNG_EIP_REV             0x007C
614d168941SAndrew F. Davis #define	RNG_MMR_STATUS_EN       0x1FD8
624d168941SAndrew F. Davis #define	RNG_REV                 0x1FE0
634d168941SAndrew F. Davis #define	RNG_SYS_CONFIG_REG      0x1FE4
644d168941SAndrew F. Davis #  define RNG_AUTOIDLE          BIT(0)
654d168941SAndrew F. Davis #define	RNG_MMR_STATUS_SET      0x1FEC
664d168941SAndrew F. Davis #define	RNG_SOFT_RESET_REG      0x1FF0
674d168941SAndrew F. Davis #  define RNG_SOFT_RESET        BIT(0)
684d168941SAndrew F. Davis #define	RNG_IRQ_EOI_REG         0x1FF4
694d168941SAndrew F. Davis #define	RNG_IRQSTATUS           0x1FF8
704d168941SAndrew F. Davis 
714d168941SAndrew F. Davis #define RNG_CONTROL_STARTUP_CYCLES_SHIFT        16
724d168941SAndrew F. Davis #define RNG_CONTROL_STARTUP_CYCLES_MASK         GENMASK_32(31, 16)
734d168941SAndrew F. Davis 
744d168941SAndrew F. Davis #define RNG_CONFIG_MAX_REFIL_CYCLES_SHIFT       16
754d168941SAndrew F. Davis #define RNG_CONFIG_MAX_REFIL_CYCLES_MASK        GENMASK_32(31, 16)
764d168941SAndrew F. Davis #define RNG_CONFIG_MIN_REFIL_CYCLES_SHIFT       0
774d168941SAndrew F. Davis #define RNG_CONFIG_MIN_REFIL_CYCLES_MASK        GENMASK_32(7, 0)
784d168941SAndrew F. Davis 
794d168941SAndrew F. Davis #define RNG_ALARMCNT_ALARM_TH_SHIFT             0
804d168941SAndrew F. Davis #define RNG_ALARMCNT_ALARM_TH_MASK              GENMASK_32(7, 0)
814d168941SAndrew F. Davis #define RNG_ALARMCNT_SHUTDOWN_TH_SHIFT          16
824d168941SAndrew F. Davis #define RNG_ALARMCNT_SHUTDOWN_TH_MASK           GENMASK_32(20, 16)
834d168941SAndrew F. Davis 
844d168941SAndrew F. Davis #define RNG_CONTROL_STARTUP_CYCLES              0xff
854d168941SAndrew F. Davis #define RNG_CONFIG_MIN_REFIL_CYCLES             0x21
864d168941SAndrew F. Davis #define RNG_CONFIG_MAX_REFIL_CYCLES             0x22
874d168941SAndrew F. Davis #define RNG_ALARM_THRESHOLD                     0xff
884d168941SAndrew F. Davis #define RNG_SHUTDOWN_THRESHOLD                  0x4
894d168941SAndrew F. Davis 
904d168941SAndrew F. Davis #define RNG_FRO_MASK    GENMASK_32(23, 0)
914d168941SAndrew F. Davis 
924d168941SAndrew F. Davis #define RNG_REG_SIZE    0x2000
934d168941SAndrew F. Davis 
944d168941SAndrew F. Davis register_phys_mem(MEM_AREA_IO_SEC, RNG_BASE, RNG_REG_SIZE);
954d168941SAndrew F. Davis 
964d168941SAndrew F. Davis static unsigned int rng_lock = SPINLOCK_UNLOCK;
974d168941SAndrew F. Davis 
984d168941SAndrew F. Davis uint8_t hw_get_random_byte(void)
994d168941SAndrew F. Davis {
1004d168941SAndrew F. Davis 	static int pos;
1014d168941SAndrew F. Davis 	static union {
1024d168941SAndrew F. Davis 		uint32_t val[2];
1034d168941SAndrew F. Davis 		uint8_t byte[8];
1044d168941SAndrew F. Davis 	} random;
1054d168941SAndrew F. Davis 	vaddr_t rng = (vaddr_t)phys_to_virt(RNG_BASE, MEM_AREA_IO_SEC);
1064d168941SAndrew F. Davis 	uint8_t ret;
1074d168941SAndrew F. Davis 
1084d168941SAndrew F. Davis 	uint32_t exceptions = thread_mask_exceptions(THREAD_EXCP_ALL);
1094d168941SAndrew F. Davis 	cpu_spin_lock(&rng_lock);
1104d168941SAndrew F. Davis 
1114d168941SAndrew F. Davis 	if (!pos) {
1124d168941SAndrew F. Davis 		/* Is the result ready (available)? */
1134d168941SAndrew F. Davis 		while (!(read32(rng + RNG_STATUS) & RNG_READY)) {
1144d168941SAndrew F. Davis 			/* Is the shutdown threshold reached? */
1154d168941SAndrew F. Davis 			if (read32(rng + RNG_STATUS) & SHUTDOWN_OFLO) {
1164d168941SAndrew F. Davis 				uint32_t alarm = read32(rng + RNG_ALARMSTOP);
1174d168941SAndrew F. Davis 				uint32_t tuning = read32(rng + RNG_FRODETUNE);
1184d168941SAndrew F. Davis 				/* Clear the alarm events */
1194d168941SAndrew F. Davis 				write32(0x0, rng + RNG_ALARMMASK);
1204d168941SAndrew F. Davis 				write32(0x0, rng + RNG_ALARMSTOP);
1214d168941SAndrew F. Davis 				/* De-tune offending FROs */
1224d168941SAndrew F. Davis 				write32(tuning ^ alarm, rng + RNG_FRODETUNE);
1234d168941SAndrew F. Davis 				/* Re-enable the shut down FROs */
1244d168941SAndrew F. Davis 				write32(RNG_FRO_MASK, rng + RNG_FROENABLE);
1254d168941SAndrew F. Davis 				/* Clear the shutdown overflow event */
1264d168941SAndrew F. Davis 				write32(SHUTDOWN_OFLO, rng + RNG_INTACK);
1274d168941SAndrew F. Davis 
1284d168941SAndrew F. Davis 				DMSG("Fixed FRO shutdown\n");
1294d168941SAndrew F. Davis 			}
1304d168941SAndrew F. Davis 		}
1314d168941SAndrew F. Davis 		/* Read random value */
1324d168941SAndrew F. Davis 		random.val[0] = read32(rng + RNG_OUTPUT_L);
1334d168941SAndrew F. Davis 		random.val[1] = read32(rng + RNG_OUTPUT_H);
1344d168941SAndrew F. Davis 		/* Acknowledge read complete */
1354d168941SAndrew F. Davis 		write32(RNG_READY, rng + RNG_INTACK);
1364d168941SAndrew F. Davis 	}
1374d168941SAndrew F. Davis 
1384d168941SAndrew F. Davis 	ret = random.byte[pos];
1394d168941SAndrew F. Davis 
1404d168941SAndrew F. Davis 	pos = (pos + 1) % 8;
1414d168941SAndrew F. Davis 
1424d168941SAndrew F. Davis 	cpu_spin_unlock(&rng_lock);
1434d168941SAndrew F. Davis 	thread_set_exceptions(exceptions);
1444d168941SAndrew F. Davis 
1454d168941SAndrew F. Davis 	return ret;
1464d168941SAndrew F. Davis }
1474d168941SAndrew F. Davis 
1484d168941SAndrew F. Davis static TEE_Result dra7_rng_init(void)
1494d168941SAndrew F. Davis {
1504d168941SAndrew F. Davis 	vaddr_t rng = (vaddr_t)phys_to_virt(RNG_BASE, MEM_AREA_IO_SEC);
1514d168941SAndrew F. Davis 	uint32_t val;
1524d168941SAndrew F. Davis 
1534d168941SAndrew F. Davis 	/* Execute a software reset */
1544d168941SAndrew F. Davis 	write32(RNG_SOFT_RESET, rng + RNG_SOFT_RESET_REG);
1554d168941SAndrew F. Davis 
1564d168941SAndrew F. Davis 	/* Wait for the software reset completion by polling */
1574d168941SAndrew F. Davis 	while (read32(rng + RNG_SOFT_RESET_REG) & RNG_SOFT_RESET)
1584d168941SAndrew F. Davis 		;
1594d168941SAndrew F. Davis 
1604d168941SAndrew F. Davis 	/* Switch to low-power operating mode */
1614d168941SAndrew F. Davis 	write32(RNG_AUTOIDLE, rng + RNG_SYS_CONFIG_REG);
1624d168941SAndrew F. Davis 
1634d168941SAndrew F. Davis 	/*
1644d168941SAndrew F. Davis 	 * Select the number of clock input cycles to the
1654d168941SAndrew F. Davis 	 * FROs between two samples
1664d168941SAndrew F. Davis 	 */
1674d168941SAndrew F. Davis 	val = 0;
1684d168941SAndrew F. Davis 
1694d168941SAndrew F. Davis 	/* Ensure initial latency */
1704d168941SAndrew F. Davis 	val |= RNG_CONFIG_MIN_REFIL_CYCLES <<
1714d168941SAndrew F. Davis 			RNG_CONFIG_MIN_REFIL_CYCLES_SHIFT;
1724d168941SAndrew F. Davis 	val |= RNG_CONFIG_MAX_REFIL_CYCLES <<
1734d168941SAndrew F. Davis 			RNG_CONFIG_MAX_REFIL_CYCLES_SHIFT;
1744d168941SAndrew F. Davis 	write32(val, rng + RNG_CONFIG);
1754d168941SAndrew F. Davis 
1764d168941SAndrew F. Davis 	/* Configure the desired FROs */
1774d168941SAndrew F. Davis 	write32(0x0, rng + RNG_FRODETUNE);
1784d168941SAndrew F. Davis 
1794d168941SAndrew F. Davis 	/* Enable all FROs */
1804d168941SAndrew F. Davis 	write32(0xffffff, rng + RNG_FROENABLE);
1814d168941SAndrew F. Davis 
1824d168941SAndrew F. Davis 	/*
1834d168941SAndrew F. Davis 	 * Select the maximum number of samples after
1844d168941SAndrew F. Davis 	 * which if a repeating pattern is still detected, an
1854d168941SAndrew F. Davis 	 * alarm event is generated
1864d168941SAndrew F. Davis 	 */
1874d168941SAndrew F. Davis 	val = RNG_ALARM_THRESHOLD << RNG_ALARMCNT_ALARM_TH_SHIFT;
1884d168941SAndrew F. Davis 
1894d168941SAndrew F. Davis 	/*
1904d168941SAndrew F. Davis 	 * Set the shutdown threshold to the number of FROs
1914d168941SAndrew F. Davis 	 * allowed to be shut downed
1924d168941SAndrew F. Davis 	 */
1934d168941SAndrew F. Davis 	val |= RNG_SHUTDOWN_THRESHOLD << RNG_ALARMCNT_SHUTDOWN_TH_SHIFT;
1944d168941SAndrew F. Davis 	write32(val, rng + RNG_ALARMCNT);
1954d168941SAndrew F. Davis 
1964d168941SAndrew F. Davis 	/* Enable the RNG module */
1974d168941SAndrew F. Davis 	val = RNG_CONTROL_STARTUP_CYCLES << RNG_CONTROL_STARTUP_CYCLES_SHIFT;
1984d168941SAndrew F. Davis 	val |= ENABLE_TRNG;
1994d168941SAndrew F. Davis 	write32(val, rng + RNG_CONTROL);
2004d168941SAndrew F. Davis 
2014d168941SAndrew F. Davis 	IMSG("DRA7x TRNG initialized");
2024d168941SAndrew F. Davis 
2034d168941SAndrew F. Davis 	return TEE_SUCCESS;
2044d168941SAndrew F. Davis }
2054d168941SAndrew F. Davis driver_init(dra7_rng_init);
206