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