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