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