/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include "ddr_parameter.h" /* * The miniloader delivers the parameters about ddr usage info from address * 0x02000000 and the data format is defined as below figure. It tells ATF the * areas of ddr that are used by platform, we treat them as non-secure regions * by default. Then we should parse the other part regions and configurate them * as secure regions to avoid illegal access. * * [ddr usage info data format] * 0x02000000 * ----------------------------------------------------------------------------- * | | | | * ----------------------------------------------------------------------------- * | count | 4byte | the array numbers of the | * | | | 'addr_array' and 'size_array' | * ----------------------------------------------------------------------------- * | reserved | 4byte | just for 'addr_array' 8byte aligned | * ----------------------------------------------------------------------------- * | addr_array[count] | per 8byte | memory region base address | * ----------------------------------------------------------------------------- * | size_array[count] | per 8byte | memory region size (byte) | * ----------------------------------------------------------------------------- */ /* * function: read parameters info(ns-regions) and try to parse s-regions info * * @addr: head address to the ddr usage struct from miniloader * @max_mb: the max ddr capacity(MB) that the platform support */ struct param_ddr_usage ddr_region_usage_parse(uint64_t addr, uint64_t max_mb) { uint64_t base, top; uint32_t i, addr_offset, size_offset; struct param_ddr_usage p; memset(&p, 0, sizeof(p)); /* read how many blocks of ns-regions, read from offset: 0x0 */ p.ns_nr = mmio_read_32(addr + REGION_NR_OFFSET); if ((p.ns_nr > DDR_REGION_NR_MAX) || (p.ns_nr == 0)) { ERROR("over or zero region, nr=%d, max=%d\n", p.ns_nr, DDR_REGION_NR_MAX); return p; } /* whole ddr regions boundary, it will be used when parse s-regions */ p.boundary = max_mb; /* calculate ns-region base addr and size offset */ addr_offset = REGION_ADDR_OFFSET; size_offset = REGION_ADDR_OFFSET + p.ns_nr * REGION_DATA_PER_BYTES; /* read all ns-regions base and top address */ for (i = 0; i < p.ns_nr; i++) { base = mmio_read_64(addr + addr_offset); top = base + mmio_read_64(addr + size_offset); /* * translate byte to MB and store info, * Miniloader will promise every ns-region is MB aligned. */ p.ns_base[i] = RG_SIZE_MB(base); p.ns_top[i] = RG_SIZE_MB(top); addr_offset += REGION_DATA_PER_BYTES; size_offset += REGION_DATA_PER_BYTES; } /* * a s-region's base starts from previous ns-region's top, and a * s-region's top ends with next ns-region's base. maybe like this: * * case1: ns-regison start from 0MB * ----------------------------------------------- * | ns0 | S0 | ns1 | S1 | ns2 | * 0----------------------------------------------- max_mb * * * case2: ns-regison not start from 0MB * ----------------------------------------------- * | S0 | ns0 | ns1 | ns2 | S1 | * 0----------------------------------------------- max_mb */ /* like above case2 figure, ns-region is not start from 0MB */ if (p.ns_base[0] != 0) { p.s_base[p.s_nr] = 0; p.s_top[p.s_nr] = p.ns_base[0]; p.s_nr++; } /* * notice: if ns-regions not start from 0MB, p.s_nr = 1 now, otherwise 0 */ for (i = 0; i < p.ns_nr; i++) { /* * if current ns-regions top covers boundary, * that means s-regions are all parsed yet, so finsh. */ if (p.ns_top[i] == p.boundary) goto out; /* s-region's base starts from previous ns-region's top */ p.s_base[p.s_nr] = p.ns_top[i]; /* s-region's top ends with next ns-region's base */ if (i + 1 < p.ns_nr) p.s_top[p.s_nr] = p.ns_base[i + 1]; else p.s_top[p.s_nr] = p.boundary; p.s_nr++; } out: return p; }