1 /* 2 * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <string.h> 8 9 #include <platform_def.h> 10 11 #include <arch_helpers.h> 12 #include <common/debug.h> 13 #include <drivers/console.h> 14 #include <drivers/delay_timer.h> 15 #include <lib/mmio.h> 16 17 #include <plat_private.h> 18 #include <soc.h> 19 20 #include "ddr_parameter.h" 21 22 /* 23 * The miniloader delivers the parameters about ddr usage info from address 24 * 0x02000000 and the data format is defined as below figure. It tells ATF the 25 * areas of ddr that are used by platform, we treat them as non-secure regions 26 * by default. Then we should parse the other part regions and configurate them 27 * as secure regions to avoid illegal access. 28 * 29 * [ddr usage info data format] 30 * 0x02000000 31 * ----------------------------------------------------------------------------- 32 * | <name> | <size> | <description> | 33 * ----------------------------------------------------------------------------- 34 * | count | 4byte | the array numbers of the | 35 * | | | 'addr_array' and 'size_array' | 36 * ----------------------------------------------------------------------------- 37 * | reserved | 4byte | just for 'addr_array' 8byte aligned | 38 * ----------------------------------------------------------------------------- 39 * | addr_array[count] | per 8byte | memory region base address | 40 * ----------------------------------------------------------------------------- 41 * | size_array[count] | per 8byte | memory region size (byte) | 42 * ----------------------------------------------------------------------------- 43 */ 44 45 /* 46 * function: read parameters info(ns-regions) and try to parse s-regions info 47 * 48 * @addr: head address to the ddr usage struct from miniloader 49 * @max_mb: the max ddr capacity(MB) that the platform support 50 */ 51 struct param_ddr_usage ddr_region_usage_parse(uint64_t addr, uint64_t max_mb) 52 { 53 uint64_t base, top; 54 uint32_t i, addr_offset, size_offset; 55 struct param_ddr_usage p; 56 57 memset(&p, 0, sizeof(p)); 58 59 /* read how many blocks of ns-regions, read from offset: 0x0 */ 60 p.ns_nr = mmio_read_32(addr + REGION_NR_OFFSET); 61 if ((p.ns_nr > DDR_REGION_NR_MAX) || (p.ns_nr == 0)) { 62 ERROR("over or zero region, nr=%d, max=%d\n", 63 p.ns_nr, DDR_REGION_NR_MAX); 64 return p; 65 } 66 67 /* whole ddr regions boundary, it will be used when parse s-regions */ 68 p.boundary = max_mb; 69 70 /* calculate ns-region base addr and size offset */ 71 addr_offset = REGION_ADDR_OFFSET; 72 size_offset = REGION_ADDR_OFFSET + p.ns_nr * REGION_DATA_PER_BYTES; 73 74 /* read all ns-regions base and top address */ 75 for (i = 0; i < p.ns_nr; i++) { 76 base = mmio_read_64(addr + addr_offset); 77 top = base + mmio_read_64(addr + size_offset); 78 /* 79 * translate byte to MB and store info, 80 * Miniloader will promise every ns-region is MB aligned. 81 */ 82 p.ns_base[i] = RG_SIZE_MB(base); 83 p.ns_top[i] = RG_SIZE_MB(top); 84 85 addr_offset += REGION_DATA_PER_BYTES; 86 size_offset += REGION_DATA_PER_BYTES; 87 } 88 89 /* 90 * a s-region's base starts from previous ns-region's top, and a 91 * s-region's top ends with next ns-region's base. maybe like this: 92 * 93 * case1: ns-regison start from 0MB 94 * ----------------------------------------------- 95 * | ns0 | S0 | ns1 | S1 | ns2 | 96 * 0----------------------------------------------- max_mb 97 * 98 * 99 * case2: ns-regison not start from 0MB 100 * ----------------------------------------------- 101 * | S0 | ns0 | ns1 | ns2 | S1 | 102 * 0----------------------------------------------- max_mb 103 */ 104 105 /* like above case2 figure, ns-region is not start from 0MB */ 106 if (p.ns_base[0] != 0) { 107 p.s_base[p.s_nr] = 0; 108 p.s_top[p.s_nr] = p.ns_base[0]; 109 p.s_nr++; 110 } 111 112 /* 113 * notice: if ns-regions not start from 0MB, p.s_nr = 1 now, otherwise 0 114 */ 115 for (i = 0; i < p.ns_nr; i++) { 116 /* 117 * if current ns-regions top covers boundary, 118 * that means s-regions are all parsed yet, so finsh. 119 */ 120 if (p.ns_top[i] == p.boundary) 121 goto out; 122 123 /* s-region's base starts from previous ns-region's top */ 124 p.s_base[p.s_nr] = p.ns_top[i]; 125 126 /* s-region's top ends with next ns-region's base */ 127 if (i + 1 < p.ns_nr) 128 p.s_top[p.s_nr] = p.ns_base[i + 1]; 129 else 130 p.s_top[p.s_nr] = p.boundary; 131 p.s_nr++; 132 } 133 out: 134 return p; 135 } 136