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 */ 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