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