1 /* 2 * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * 7 * Redistributions of source code must retain the above copyright notice, this 8 * list of conditions and the following disclaimer. 9 * 10 * Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 14 * Neither the name of ARM nor the names of its contributors may be used 15 * to endorse or promote products derived from this software without specific 16 * prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <arch_helpers.h> 32 #include <console.h> 33 #include <debug.h> 34 #include <delay_timer.h> 35 #include <mmio.h> 36 #include <platform_def.h> 37 #include <plat_private.h> 38 #include <soc.h> 39 #include <string.h> 40 #include "ddr_parameter.h" 41 42 /* 43 * The miniloader delivers the parameters about ddr usage info from address 44 * 0x02000000 and the data format is defined as below figure. It tells ATF the 45 * areas of ddr that are used by platform, we treat them as non-secure regions 46 * by default. Then we should parse the other part regions and configurate them 47 * as secure regions to avoid illegal access. 48 * 49 * [ddr usage info data format] 50 * 0x02000000 51 * ----------------------------------------------------------------------------- 52 * | <name> | <size> | <description> | 53 * ----------------------------------------------------------------------------- 54 * | count | 4byte | the array numbers of the | 55 * | | | 'addr_array' and 'size_array' | 56 * ----------------------------------------------------------------------------- 57 * | reserved | 4byte | just for 'addr_array' 8byte aligned | 58 * ----------------------------------------------------------------------------- 59 * | addr_array[count] | per 8byte | memory region base address | 60 * ----------------------------------------------------------------------------- 61 * | size_array[count] | per 8byte | memory region size (byte) | 62 * ----------------------------------------------------------------------------- 63 */ 64 65 /* 66 * function: read parameters info(ns-regions) and try to parse s-regions info 67 * 68 * @addr: head address to the ddr usage struct from miniloader 69 * @max_mb: the max ddr capacity(MB) that the platform support 70 */ 71 struct param_ddr_usage ddr_region_usage_parse(uint64_t addr, uint64_t max_mb) 72 { 73 uint64_t base, top; 74 uint32_t i, addr_offset, size_offset; 75 struct param_ddr_usage p; 76 77 memset(&p, 0, sizeof(p)); 78 79 /* read how many blocks of ns-regions, read from offset: 0x0 */ 80 p.ns_nr = mmio_read_32(addr + REGION_NR_OFFSET); 81 if ((p.ns_nr > DDR_REGION_NR_MAX) || (p.ns_nr == 0)) { 82 ERROR("over or zero region, nr=%d, max=%d\n", 83 p.ns_nr, DDR_REGION_NR_MAX); 84 return p; 85 } 86 87 /* whole ddr regions boundary, it will be used when parse s-regions */ 88 p.boundary = max_mb; 89 90 /* calculate ns-region base addr and size offset */ 91 addr_offset = REGION_ADDR_OFFSET; 92 size_offset = REGION_ADDR_OFFSET + p.ns_nr * REGION_DATA_PER_BYTES; 93 94 /* read all ns-regions base and top address */ 95 for (i = 0; i < p.ns_nr; i++) { 96 base = mmio_read_64(addr + addr_offset); 97 top = base + mmio_read_64(addr + size_offset); 98 /* 99 * translate byte to MB and store info, 100 * Miniloader will promise every ns-region is MB aligned. 101 */ 102 p.ns_base[i] = RG_SIZE_MB(base); 103 p.ns_top[i] = RG_SIZE_MB(top); 104 105 addr_offset += REGION_DATA_PER_BYTES; 106 size_offset += REGION_DATA_PER_BYTES; 107 } 108 109 /* 110 * a s-region's base starts from previous ns-region's top, and a 111 * s-region's top ends with next ns-region's base. maybe like this: 112 * 113 * case1: ns-regison start from 0MB 114 * ----------------------------------------------- 115 * | ns0 | S0 | ns1 | S1 | ns2 | 116 * 0----------------------------------------------- max_mb 117 * 118 * 119 * case2: ns-regison not start from 0MB 120 * ----------------------------------------------- 121 * | S0 | ns0 | ns1 | ns2 | S1 | 122 * 0----------------------------------------------- max_mb 123 */ 124 125 /* like above case2 figure, ns-region is not start from 0MB */ 126 if (p.ns_base[0] != 0) { 127 p.s_base[p.s_nr] = 0; 128 p.s_top[p.s_nr] = p.ns_base[0]; 129 p.s_nr++; 130 } 131 132 /* 133 * notice: if ns-regions not start from 0MB, p.s_nr = 1 now, otherwise 0 134 */ 135 for (i = 0; i < p.ns_nr; i++) { 136 /* 137 * if current ns-regions top covers boundary, 138 * that means s-regions are all parsed yet, so finsh. 139 */ 140 if (p.ns_top[i] == p.boundary) 141 goto out; 142 143 /* s-region's base starts from previous ns-region's top */ 144 p.s_base[p.s_nr] = p.ns_top[i]; 145 146 /* s-region's top ends with next ns-region's base */ 147 if (i + 1 < p.ns_nr) 148 p.s_top[p.s_nr] = p.ns_base[i + 1]; 149 else 150 p.s_top[p.s_nr] = p.boundary; 151 p.s_nr++; 152 } 153 out: 154 return p; 155 } 156