xref: /rk3399_ARM-atf/plat/rockchip/common/drivers/parameter/ddr_parameter.c (revision c3e70be1c1ad2a9d1d3aee187231f5088a880ae1)
10d5ec955Stony.xie /*
20d5ec955Stony.xie  * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
30d5ec955Stony.xie  *
4*c3e70be1Sdp-arm  * SPDX-License-Identifier: BSD-3-Clause
50d5ec955Stony.xie  */
60d5ec955Stony.xie 
70d5ec955Stony.xie #include <arch_helpers.h>
80d5ec955Stony.xie #include <console.h>
90d5ec955Stony.xie #include <debug.h>
100d5ec955Stony.xie #include <delay_timer.h>
110d5ec955Stony.xie #include <mmio.h>
120d5ec955Stony.xie #include <platform_def.h>
130d5ec955Stony.xie #include <plat_private.h>
140d5ec955Stony.xie #include <soc.h>
150d5ec955Stony.xie #include <string.h>
160d5ec955Stony.xie #include "ddr_parameter.h"
170d5ec955Stony.xie 
180d5ec955Stony.xie /*
190d5ec955Stony.xie  *  The miniloader delivers the parameters about ddr usage info from address
200d5ec955Stony.xie  * 0x02000000 and the data format is defined as below figure. It tells ATF the
210d5ec955Stony.xie  * areas of ddr that are used by platform, we treat them as non-secure regions
220d5ec955Stony.xie  * by default. Then we should parse the other part regions and configurate them
230d5ec955Stony.xie  * as secure regions to avoid illegal access.
240d5ec955Stony.xie  *
250d5ec955Stony.xie  *			[ddr usage info data format]
260d5ec955Stony.xie  * 0x02000000
270d5ec955Stony.xie  * -----------------------------------------------------------------------------
280d5ec955Stony.xie  * |       <name>        |  <size>   |      <description>                      |
290d5ec955Stony.xie  * -----------------------------------------------------------------------------
300d5ec955Stony.xie  * | count               |  4byte    | the array numbers of the                |
310d5ec955Stony.xie  * |                     |           | 'addr_array' and 'size_array'           |
320d5ec955Stony.xie  * -----------------------------------------------------------------------------
330d5ec955Stony.xie  * | reserved            |  4byte    | just for 'addr_array' 8byte aligned     |
340d5ec955Stony.xie  * -----------------------------------------------------------------------------
350d5ec955Stony.xie  * | addr_array[count]   | per 8byte | memory region base address              |
360d5ec955Stony.xie  * -----------------------------------------------------------------------------
370d5ec955Stony.xie  * | size_array[count]   | per 8byte | memory region size (byte)               |
380d5ec955Stony.xie  * -----------------------------------------------------------------------------
390d5ec955Stony.xie  */
400d5ec955Stony.xie 
410d5ec955Stony.xie /*
420d5ec955Stony.xie  * function: read parameters info(ns-regions) and try to parse s-regions info
430d5ec955Stony.xie  *
440d5ec955Stony.xie  * @addr: head address to the ddr usage struct from miniloader
450d5ec955Stony.xie  * @max_mb: the max ddr capacity(MB) that the platform support
460d5ec955Stony.xie  */
470d5ec955Stony.xie struct param_ddr_usage ddr_region_usage_parse(uint64_t addr, uint64_t max_mb)
480d5ec955Stony.xie {
490d5ec955Stony.xie 	uint64_t base, top;
500d5ec955Stony.xie 	uint32_t i, addr_offset, size_offset;
510d5ec955Stony.xie 	struct param_ddr_usage p;
520d5ec955Stony.xie 
530d5ec955Stony.xie 	memset(&p, 0, sizeof(p));
540d5ec955Stony.xie 
550d5ec955Stony.xie 	/* read how many blocks of ns-regions, read from offset: 0x0 */
560d5ec955Stony.xie 	p.ns_nr = mmio_read_32(addr + REGION_NR_OFFSET);
570d5ec955Stony.xie 	if ((p.ns_nr > DDR_REGION_NR_MAX) || (p.ns_nr == 0)) {
580d5ec955Stony.xie 		ERROR("over or zero region, nr=%d, max=%d\n",
590d5ec955Stony.xie 		      p.ns_nr, DDR_REGION_NR_MAX);
600d5ec955Stony.xie 		return p;
610d5ec955Stony.xie 	}
620d5ec955Stony.xie 
630d5ec955Stony.xie 	/* whole ddr regions boundary, it will be used when parse s-regions */
640d5ec955Stony.xie 	p.boundary = max_mb;
650d5ec955Stony.xie 
660d5ec955Stony.xie 	/* calculate ns-region base addr and size offset */
670d5ec955Stony.xie 	addr_offset = REGION_ADDR_OFFSET;
680d5ec955Stony.xie 	size_offset = REGION_ADDR_OFFSET + p.ns_nr * REGION_DATA_PER_BYTES;
690d5ec955Stony.xie 
700d5ec955Stony.xie 	/* read all ns-regions base and top address */
710d5ec955Stony.xie 	for (i = 0; i < p.ns_nr; i++) {
720d5ec955Stony.xie 		base = mmio_read_64(addr + addr_offset);
730d5ec955Stony.xie 		top = base + mmio_read_64(addr + size_offset);
740d5ec955Stony.xie 		/*
750d5ec955Stony.xie 		 * translate byte to MB and store info,
760d5ec955Stony.xie 		 * Miniloader will promise every ns-region is MB aligned.
770d5ec955Stony.xie 		 */
780d5ec955Stony.xie 		p.ns_base[i] = RG_SIZE_MB(base);
790d5ec955Stony.xie 		p.ns_top[i] = RG_SIZE_MB(top);
800d5ec955Stony.xie 
810d5ec955Stony.xie 		addr_offset += REGION_DATA_PER_BYTES;
820d5ec955Stony.xie 		size_offset += REGION_DATA_PER_BYTES;
830d5ec955Stony.xie 	}
840d5ec955Stony.xie 
850d5ec955Stony.xie 	/*
860d5ec955Stony.xie 	 * a s-region's base starts from previous ns-region's top, and a
870d5ec955Stony.xie 	 * s-region's top ends with next ns-region's base. maybe like this:
880d5ec955Stony.xie 	 *
890d5ec955Stony.xie 	 *	   case1: ns-regison start from 0MB
900d5ec955Stony.xie 	 *	 -----------------------------------------------
910d5ec955Stony.xie 	 *	 |    ns0   |  S0  |  ns1  |   S1  |    ns2    |
920d5ec955Stony.xie 	 *	0----------------------------------------------- max_mb
930d5ec955Stony.xie 	 *
940d5ec955Stony.xie 	 *
950d5ec955Stony.xie 	 *	   case2: ns-regison not start from 0MB
960d5ec955Stony.xie 	 *	 -----------------------------------------------
970d5ec955Stony.xie 	 *	 |    S0   |  ns0  |  ns1  |   ns2  |    S1    |
980d5ec955Stony.xie 	 *	0----------------------------------------------- max_mb
990d5ec955Stony.xie 	 */
1000d5ec955Stony.xie 
1010d5ec955Stony.xie 	/* like above case2 figure, ns-region is not start from 0MB */
1020d5ec955Stony.xie 	if (p.ns_base[0] != 0) {
1030d5ec955Stony.xie 		p.s_base[p.s_nr] = 0;
1040d5ec955Stony.xie 		p.s_top[p.s_nr] = p.ns_base[0];
1050d5ec955Stony.xie 		p.s_nr++;
1060d5ec955Stony.xie 	}
1070d5ec955Stony.xie 
1080d5ec955Stony.xie 	/*
1090d5ec955Stony.xie 	 * notice: if ns-regions not start from 0MB, p.s_nr = 1 now, otherwise 0
1100d5ec955Stony.xie 	 */
1110d5ec955Stony.xie 	for (i = 0; i < p.ns_nr; i++) {
1120d5ec955Stony.xie 		/*
1130d5ec955Stony.xie 		 * if current ns-regions top covers boundary,
1140d5ec955Stony.xie 		 * that means s-regions are all parsed yet, so finsh.
1150d5ec955Stony.xie 		 */
1160d5ec955Stony.xie 		if (p.ns_top[i] == p.boundary)
1170d5ec955Stony.xie 			goto out;
1180d5ec955Stony.xie 
1190d5ec955Stony.xie 		/* s-region's base starts from previous ns-region's top */
1200d5ec955Stony.xie 		p.s_base[p.s_nr] = p.ns_top[i];
1210d5ec955Stony.xie 
1220d5ec955Stony.xie 		/* s-region's top ends with next ns-region's base */
1230d5ec955Stony.xie 		if (i + 1 < p.ns_nr)
1240d5ec955Stony.xie 			p.s_top[p.s_nr] = p.ns_base[i + 1];
1250d5ec955Stony.xie 		else
1260d5ec955Stony.xie 			p.s_top[p.s_nr] = p.boundary;
1270d5ec955Stony.xie 		p.s_nr++;
1280d5ec955Stony.xie 	}
1290d5ec955Stony.xie out:
1300d5ec955Stony.xie 	return p;
1310d5ec955Stony.xie }
132